From 8d89554d8432c6802f65f932eee3b20773d42eab Mon Sep 17 00:00:00 2001 From: Gislain Harding Date: Mon, 7 Sep 2020 10:10:13 +0200 Subject: [PATCH 001/187] Set formula attribute in the Xlsx reader --- src/PhpSpreadsheet/Reader/Xlsx.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 73f91852..8d38fa3e 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -717,6 +717,10 @@ class Xlsx extends BaseReader } else { // Formula $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString'); + if (isset($c->f['t'])) { + $att = $c->f['t']; + $docSheet->getCell($r)->setFormulaAttributes(['t' => (string)$att]); + } } break; From 002044cce98ef32aa80a5f3e0d303bf0d5908951 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 29 Dec 2020 18:19:43 +0100 Subject: [PATCH 002/187] Update Units of Measure supported by the CONVERT() function (#1768) Now supports all current UoM in all categories, with both 1- and 2-character multiplier prefixes, and binary multiplier prefixes, including the new Temperature scales --- CHANGELOG.md | 2 +- .../Calculation/Engineering.php | 857 +----------------- .../Calculation/Engineering/ConvertUOM.php | 684 ++++++++++++++ .../Calculation/Engineering/CONVERTUOM.php | 202 +++-- 4 files changed, 856 insertions(+), 889 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e7b13a..b8e37e66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Changed -- Nothing. +- Updated the CONVERT() function to support all current MS Excel categories and Units of Measure. ### Deprecated diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 1256dd90..57116f28 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use Complex\Complex; use Complex\Exception as ComplexException; +use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM; class Engineering { @@ -12,710 +13,6 @@ class Engineering */ const EULER = 2.71828182845904523536; - /** - * Details of the Units of measure that can be used in CONVERTUOM(). - * - * @var mixed[] - */ - private static $conversionUnits = [ - 'g' => ['Group' => 'Mass', 'Unit Name' => 'Gram', 'AllowPrefix' => true], - 'sg' => ['Group' => 'Mass', 'Unit Name' => 'Slug', 'AllowPrefix' => false], - 'lbm' => ['Group' => 'Mass', 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false], - 'u' => ['Group' => 'Mass', 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => true], - 'ozm' => ['Group' => 'Mass', 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false], - 'm' => ['Group' => 'Distance', 'Unit Name' => 'Meter', 'AllowPrefix' => true], - 'mi' => ['Group' => 'Distance', 'Unit Name' => 'Statute mile', 'AllowPrefix' => false], - 'Nmi' => ['Group' => 'Distance', 'Unit Name' => 'Nautical mile', 'AllowPrefix' => false], - 'in' => ['Group' => 'Distance', 'Unit Name' => 'Inch', 'AllowPrefix' => false], - 'ft' => ['Group' => 'Distance', 'Unit Name' => 'Foot', 'AllowPrefix' => false], - 'yd' => ['Group' => 'Distance', 'Unit Name' => 'Yard', 'AllowPrefix' => false], - 'ang' => ['Group' => 'Distance', 'Unit Name' => 'Angstrom', 'AllowPrefix' => true], - 'Pica' => ['Group' => 'Distance', 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false], - 'yr' => ['Group' => 'Time', 'Unit Name' => 'Year', 'AllowPrefix' => false], - 'day' => ['Group' => 'Time', 'Unit Name' => 'Day', 'AllowPrefix' => false], - 'hr' => ['Group' => 'Time', 'Unit Name' => 'Hour', 'AllowPrefix' => false], - 'mn' => ['Group' => 'Time', 'Unit Name' => 'Minute', 'AllowPrefix' => false], - 'sec' => ['Group' => 'Time', 'Unit Name' => 'Second', 'AllowPrefix' => true], - 'Pa' => ['Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true], - 'p' => ['Group' => 'Pressure', 'Unit Name' => 'Pascal', 'AllowPrefix' => true], - 'atm' => ['Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true], - 'at' => ['Group' => 'Pressure', 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true], - 'mmHg' => ['Group' => 'Pressure', 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => true], - 'N' => ['Group' => 'Force', 'Unit Name' => 'Newton', 'AllowPrefix' => true], - 'dyn' => ['Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true], - 'dy' => ['Group' => 'Force', 'Unit Name' => 'Dyne', 'AllowPrefix' => true], - 'lbf' => ['Group' => 'Force', 'Unit Name' => 'Pound force', 'AllowPrefix' => false], - 'J' => ['Group' => 'Energy', 'Unit Name' => 'Joule', 'AllowPrefix' => true], - 'e' => ['Group' => 'Energy', 'Unit Name' => 'Erg', 'AllowPrefix' => true], - 'c' => ['Group' => 'Energy', 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => true], - 'cal' => ['Group' => 'Energy', 'Unit Name' => 'IT calorie', 'AllowPrefix' => true], - 'eV' => ['Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true], - 'ev' => ['Group' => 'Energy', 'Unit Name' => 'Electron volt', 'AllowPrefix' => true], - 'HPh' => ['Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false], - 'hh' => ['Group' => 'Energy', 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false], - 'Wh' => ['Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true], - 'wh' => ['Group' => 'Energy', 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true], - 'flb' => ['Group' => 'Energy', 'Unit Name' => 'Foot-pound', 'AllowPrefix' => false], - 'BTU' => ['Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false], - 'btu' => ['Group' => 'Energy', 'Unit Name' => 'BTU', 'AllowPrefix' => false], - 'HP' => ['Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false], - 'h' => ['Group' => 'Power', 'Unit Name' => 'Horsepower', 'AllowPrefix' => false], - 'W' => ['Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true], - 'w' => ['Group' => 'Power', 'Unit Name' => 'Watt', 'AllowPrefix' => true], - 'T' => ['Group' => 'Magnetism', 'Unit Name' => 'Tesla', 'AllowPrefix' => true], - 'ga' => ['Group' => 'Magnetism', 'Unit Name' => 'Gauss', 'AllowPrefix' => true], - 'C' => ['Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false], - 'cel' => ['Group' => 'Temperature', 'Unit Name' => 'Celsius', 'AllowPrefix' => false], - 'F' => ['Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false], - 'fah' => ['Group' => 'Temperature', 'Unit Name' => 'Fahrenheit', 'AllowPrefix' => false], - 'K' => ['Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false], - 'kel' => ['Group' => 'Temperature', 'Unit Name' => 'Kelvin', 'AllowPrefix' => false], - 'tsp' => ['Group' => 'Liquid', 'Unit Name' => 'Teaspoon', 'AllowPrefix' => false], - 'tbs' => ['Group' => 'Liquid', 'Unit Name' => 'Tablespoon', 'AllowPrefix' => false], - 'oz' => ['Group' => 'Liquid', 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => false], - 'cup' => ['Group' => 'Liquid', 'Unit Name' => 'Cup', 'AllowPrefix' => false], - 'pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false], - 'us_pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false], - 'uk_pt' => ['Group' => 'Liquid', 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => false], - 'qt' => ['Group' => 'Liquid', 'Unit Name' => 'Quart', 'AllowPrefix' => false], - 'gal' => ['Group' => 'Liquid', 'Unit Name' => 'Gallon', 'AllowPrefix' => false], - 'l' => ['Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true], - 'lt' => ['Group' => 'Liquid', 'Unit Name' => 'Litre', 'AllowPrefix' => true], - ]; - - /** - * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). - * - * @var mixed[] - */ - private static $conversionMultipliers = [ - 'Y' => ['multiplier' => 1E24, 'name' => 'yotta'], - 'Z' => ['multiplier' => 1E21, 'name' => 'zetta'], - 'E' => ['multiplier' => 1E18, 'name' => 'exa'], - 'P' => ['multiplier' => 1E15, 'name' => 'peta'], - 'T' => ['multiplier' => 1E12, 'name' => 'tera'], - 'G' => ['multiplier' => 1E9, 'name' => 'giga'], - 'M' => ['multiplier' => 1E6, 'name' => 'mega'], - 'k' => ['multiplier' => 1E3, 'name' => 'kilo'], - 'h' => ['multiplier' => 1E2, 'name' => 'hecto'], - 'e' => ['multiplier' => 1E1, 'name' => 'deka'], - 'd' => ['multiplier' => 1E-1, 'name' => 'deci'], - 'c' => ['multiplier' => 1E-2, 'name' => 'centi'], - 'm' => ['multiplier' => 1E-3, 'name' => 'milli'], - 'u' => ['multiplier' => 1E-6, 'name' => 'micro'], - 'n' => ['multiplier' => 1E-9, 'name' => 'nano'], - 'p' => ['multiplier' => 1E-12, 'name' => 'pico'], - 'f' => ['multiplier' => 1E-15, 'name' => 'femto'], - 'a' => ['multiplier' => 1E-18, 'name' => 'atto'], - 'z' => ['multiplier' => 1E-21, 'name' => 'zepto'], - 'y' => ['multiplier' => 1E-24, 'name' => 'yocto'], - ]; - - /** - * Details of the Units of measure conversion factors, organised by group. - * - * @var mixed[] - */ - private static $unitConversions = [ - 'Mass' => [ - 'g' => [ - 'g' => 1.0, - 'sg' => 6.85220500053478E-05, - 'lbm' => 2.20462291469134E-03, - 'u' => 6.02217000000000E+23, - 'ozm' => 3.52739718003627E-02, - ], - 'sg' => [ - 'g' => 1.45938424189287E+04, - 'sg' => 1.0, - 'lbm' => 3.21739194101647E+01, - 'u' => 8.78866000000000E+27, - 'ozm' => 5.14782785944229E+02, - ], - 'lbm' => [ - 'g' => 4.5359230974881148E+02, - 'sg' => 3.10810749306493E-02, - 'lbm' => 1.0, - 'u' => 2.73161000000000E+26, - 'ozm' => 1.60000023429410E+01, - ], - 'u' => [ - 'g' => 1.66053100460465E-24, - 'sg' => 1.13782988532950E-28, - 'lbm' => 3.66084470330684E-27, - 'u' => 1.0, - 'ozm' => 5.85735238300524E-26, - ], - 'ozm' => [ - 'g' => 2.83495152079732E+01, - 'sg' => 1.94256689870811E-03, - 'lbm' => 6.24999908478882E-02, - 'u' => 1.70725600000000E+25, - 'ozm' => 1.0, - ], - ], - 'Distance' => [ - 'm' => [ - 'm' => 1.0, - 'mi' => 6.21371192237334E-04, - 'Nmi' => 5.39956803455724E-04, - 'in' => 3.93700787401575E+01, - 'ft' => 3.28083989501312E+00, - 'yd' => 1.09361329797891E+00, - 'ang' => 1.00000000000000E+10, - 'Pica' => 2.83464566929116E+03, - ], - 'mi' => [ - 'm' => 1.60934400000000E+03, - 'mi' => 1.0, - 'Nmi' => 8.68976241900648E-01, - 'in' => 6.33600000000000E+04, - 'ft' => 5.28000000000000E+03, - 'yd' => 1.76000000000000E+03, - 'ang' => 1.60934400000000E+13, - 'Pica' => 4.56191999999971E+06, - ], - 'Nmi' => [ - 'm' => 1.85200000000000E+03, - 'mi' => 1.15077944802354E+00, - 'Nmi' => 1.0, - 'in' => 7.29133858267717E+04, - 'ft' => 6.07611548556430E+03, - 'yd' => 2.02537182785694E+03, - 'ang' => 1.85200000000000E+13, - 'Pica' => 5.24976377952723E+06, - ], - 'in' => [ - 'm' => 2.54000000000000E-02, - 'mi' => 1.57828282828283E-05, - 'Nmi' => 1.37149028077754E-05, - 'in' => 1.0, - 'ft' => 8.33333333333333E-02, - 'yd' => 2.77777777686643E-02, - 'ang' => 2.54000000000000E+08, - 'Pica' => 7.19999999999955E+01, - ], - 'ft' => [ - 'm' => 3.04800000000000E-01, - 'mi' => 1.89393939393939E-04, - 'Nmi' => 1.64578833693305E-04, - 'in' => 1.20000000000000E+01, - 'ft' => 1.0, - 'yd' => 3.33333333223972E-01, - 'ang' => 3.04800000000000E+09, - 'Pica' => 8.63999999999946E+02, - ], - 'yd' => [ - 'm' => 9.14400000300000E-01, - 'mi' => 5.68181818368230E-04, - 'Nmi' => 4.93736501241901E-04, - 'in' => 3.60000000118110E+01, - 'ft' => 3.00000000000000E+00, - 'yd' => 1.0, - 'ang' => 9.14400000300000E+09, - 'Pica' => 2.59200000085023E+03, - ], - 'ang' => [ - 'm' => 1.00000000000000E-10, - 'mi' => 6.21371192237334E-14, - 'Nmi' => 5.39956803455724E-14, - 'in' => 3.93700787401575E-09, - 'ft' => 3.28083989501312E-10, - 'yd' => 1.09361329797891E-10, - 'ang' => 1.0, - 'Pica' => 2.83464566929116E-07, - ], - 'Pica' => [ - 'm' => 3.52777777777800E-04, - 'mi' => 2.19205948372629E-07, - 'Nmi' => 1.90484761219114E-07, - 'in' => 1.38888888888898E-02, - 'ft' => 1.15740740740748E-03, - 'yd' => 3.85802469009251E-04, - 'ang' => 3.52777777777800E+06, - 'Pica' => 1.0, - ], - ], - 'Time' => [ - 'yr' => [ - 'yr' => 1.0, - 'day' => 365.25, - 'hr' => 8766.0, - 'mn' => 525960.0, - 'sec' => 31557600.0, - ], - 'day' => [ - 'yr' => 2.73785078713210E-03, - 'day' => 1.0, - 'hr' => 24.0, - 'mn' => 1440.0, - 'sec' => 86400.0, - ], - 'hr' => [ - 'yr' => 1.14077116130504E-04, - 'day' => 4.16666666666667E-02, - 'hr' => 1.0, - 'mn' => 60.0, - 'sec' => 3600.0, - ], - 'mn' => [ - 'yr' => 1.90128526884174E-06, - 'day' => 6.94444444444444E-04, - 'hr' => 1.66666666666667E-02, - 'mn' => 1.0, - 'sec' => 60.0, - ], - 'sec' => [ - 'yr' => 3.16880878140289E-08, - 'day' => 1.15740740740741E-05, - 'hr' => 2.77777777777778E-04, - 'mn' => 1.66666666666667E-02, - 'sec' => 1.0, - ], - ], - 'Pressure' => [ - 'Pa' => [ - 'Pa' => 1.0, - 'p' => 1.0, - 'atm' => 9.86923299998193E-06, - 'at' => 9.86923299998193E-06, - 'mmHg' => 7.50061707998627E-03, - ], - 'p' => [ - 'Pa' => 1.0, - 'p' => 1.0, - 'atm' => 9.86923299998193E-06, - 'at' => 9.86923299998193E-06, - 'mmHg' => 7.50061707998627E-03, - ], - 'atm' => [ - 'Pa' => 1.01324996583000E+05, - 'p' => 1.01324996583000E+05, - 'atm' => 1.0, - 'at' => 1.0, - 'mmHg' => 760.0, - ], - 'at' => [ - 'Pa' => 1.01324996583000E+05, - 'p' => 1.01324996583000E+05, - 'atm' => 1.0, - 'at' => 1.0, - 'mmHg' => 760.0, - ], - 'mmHg' => [ - 'Pa' => 1.33322363925000E+02, - 'p' => 1.33322363925000E+02, - 'atm' => 1.31578947368421E-03, - 'at' => 1.31578947368421E-03, - 'mmHg' => 1.0, - ], - ], - 'Force' => [ - 'N' => [ - 'N' => 1.0, - 'dyn' => 1.0E+5, - 'dy' => 1.0E+5, - 'lbf' => 2.24808923655339E-01, - ], - 'dyn' => [ - 'N' => 1.0E-5, - 'dyn' => 1.0, - 'dy' => 1.0, - 'lbf' => 2.24808923655339E-06, - ], - 'dy' => [ - 'N' => 1.0E-5, - 'dyn' => 1.0, - 'dy' => 1.0, - 'lbf' => 2.24808923655339E-06, - ], - 'lbf' => [ - 'N' => 4.448222, - 'dyn' => 4.448222E+5, - 'dy' => 4.448222E+5, - 'lbf' => 1.0, - ], - ], - 'Energy' => [ - 'J' => [ - 'J' => 1.0, - 'e' => 9.99999519343231E+06, - 'c' => 2.39006249473467E-01, - 'cal' => 2.38846190642017E-01, - 'eV' => 6.24145700000000E+18, - 'ev' => 6.24145700000000E+18, - 'HPh' => 3.72506430801000E-07, - 'hh' => 3.72506430801000E-07, - 'Wh' => 2.77777916238711E-04, - 'wh' => 2.77777916238711E-04, - 'flb' => 2.37304222192651E+01, - 'BTU' => 9.47815067349015E-04, - 'btu' => 9.47815067349015E-04, - ], - 'e' => [ - 'J' => 1.00000048065700E-07, - 'e' => 1.0, - 'c' => 2.39006364353494E-08, - 'cal' => 2.38846305445111E-08, - 'eV' => 6.24146000000000E+11, - 'ev' => 6.24146000000000E+11, - 'HPh' => 3.72506609848824E-14, - 'hh' => 3.72506609848824E-14, - 'Wh' => 2.77778049754611E-11, - 'wh' => 2.77778049754611E-11, - 'flb' => 2.37304336254586E-06, - 'BTU' => 9.47815522922962E-11, - 'btu' => 9.47815522922962E-11, - ], - 'c' => [ - 'J' => 4.18399101363672E+00, - 'e' => 4.18398900257312E+07, - 'c' => 1.0, - 'cal' => 9.99330315287563E-01, - 'eV' => 2.61142000000000E+19, - 'ev' => 2.61142000000000E+19, - 'HPh' => 1.55856355899327E-06, - 'hh' => 1.55856355899327E-06, - 'Wh' => 1.16222030532950E-03, - 'wh' => 1.16222030532950E-03, - 'flb' => 9.92878733152102E+01, - 'BTU' => 3.96564972437776E-03, - 'btu' => 3.96564972437776E-03, - ], - 'cal' => [ - 'J' => 4.18679484613929E+00, - 'e' => 4.18679283372801E+07, - 'c' => 1.00067013349059E+00, - 'cal' => 1.0, - 'eV' => 2.61317000000000E+19, - 'ev' => 2.61317000000000E+19, - 'HPh' => 1.55960800463137E-06, - 'hh' => 1.55960800463137E-06, - 'Wh' => 1.16299914807955E-03, - 'wh' => 1.16299914807955E-03, - 'flb' => 9.93544094443283E+01, - 'BTU' => 3.96830723907002E-03, - 'btu' => 3.96830723907002E-03, - ], - 'eV' => [ - 'J' => 1.60219000146921E-19, - 'e' => 1.60218923136574E-12, - 'c' => 3.82933423195043E-20, - 'cal' => 3.82676978535648E-20, - 'eV' => 1.0, - 'ev' => 1.0, - 'HPh' => 5.96826078912344E-26, - 'hh' => 5.96826078912344E-26, - 'Wh' => 4.45053000026614E-23, - 'wh' => 4.45053000026614E-23, - 'flb' => 3.80206452103492E-18, - 'BTU' => 1.51857982414846E-22, - 'btu' => 1.51857982414846E-22, - ], - 'ev' => [ - 'J' => 1.60219000146921E-19, - 'e' => 1.60218923136574E-12, - 'c' => 3.82933423195043E-20, - 'cal' => 3.82676978535648E-20, - 'eV' => 1.0, - 'ev' => 1.0, - 'HPh' => 5.96826078912344E-26, - 'hh' => 5.96826078912344E-26, - 'Wh' => 4.45053000026614E-23, - 'wh' => 4.45053000026614E-23, - 'flb' => 3.80206452103492E-18, - 'BTU' => 1.51857982414846E-22, - 'btu' => 1.51857982414846E-22, - ], - 'HPh' => [ - 'J' => 2.68451741316170E+06, - 'e' => 2.68451612283024E+13, - 'c' => 6.41616438565991E+05, - 'cal' => 6.41186757845835E+05, - 'eV' => 1.67553000000000E+25, - 'ev' => 1.67553000000000E+25, - 'HPh' => 1.0, - 'hh' => 1.0, - 'Wh' => 7.45699653134593E+02, - 'wh' => 7.45699653134593E+02, - 'flb' => 6.37047316692964E+07, - 'BTU' => 2.54442605275546E+03, - 'btu' => 2.54442605275546E+03, - ], - 'hh' => [ - 'J' => 2.68451741316170E+06, - 'e' => 2.68451612283024E+13, - 'c' => 6.41616438565991E+05, - 'cal' => 6.41186757845835E+05, - 'eV' => 1.67553000000000E+25, - 'ev' => 1.67553000000000E+25, - 'HPh' => 1.0, - 'hh' => 1.0, - 'Wh' => 7.45699653134593E+02, - 'wh' => 7.45699653134593E+02, - 'flb' => 6.37047316692964E+07, - 'BTU' => 2.54442605275546E+03, - 'btu' => 2.54442605275546E+03, - ], - 'Wh' => [ - 'J' => 3.59999820554720E+03, - 'e' => 3.59999647518369E+10, - 'c' => 8.60422069219046E+02, - 'cal' => 8.59845857713046E+02, - 'eV' => 2.24692340000000E+22, - 'ev' => 2.24692340000000E+22, - 'HPh' => 1.34102248243839E-03, - 'hh' => 1.34102248243839E-03, - 'Wh' => 1.0, - 'wh' => 1.0, - 'flb' => 8.54294774062316E+04, - 'BTU' => 3.41213254164705E+00, - 'btu' => 3.41213254164705E+00, - ], - 'wh' => [ - 'J' => 3.59999820554720E+03, - 'e' => 3.59999647518369E+10, - 'c' => 8.60422069219046E+02, - 'cal' => 8.59845857713046E+02, - 'eV' => 2.24692340000000E+22, - 'ev' => 2.24692340000000E+22, - 'HPh' => 1.34102248243839E-03, - 'hh' => 1.34102248243839E-03, - 'Wh' => 1.0, - 'wh' => 1.0, - 'flb' => 8.54294774062316E+04, - 'BTU' => 3.41213254164705E+00, - 'btu' => 3.41213254164705E+00, - ], - 'flb' => [ - 'J' => 4.21400003236424E-02, - 'e' => 4.21399800687660E+05, - 'c' => 1.00717234301644E-02, - 'cal' => 1.00649785509554E-02, - 'eV' => 2.63015000000000E+17, - 'ev' => 2.63015000000000E+17, - 'HPh' => 1.56974211145130E-08, - 'hh' => 1.56974211145130E-08, - 'Wh' => 1.17055614802000E-05, - 'wh' => 1.17055614802000E-05, - 'flb' => 1.0, - 'BTU' => 3.99409272448406E-05, - 'btu' => 3.99409272448406E-05, - ], - 'BTU' => [ - 'J' => 1.05505813786749E+03, - 'e' => 1.05505763074665E+10, - 'c' => 2.52165488508168E+02, - 'cal' => 2.51996617135510E+02, - 'eV' => 6.58510000000000E+21, - 'ev' => 6.58510000000000E+21, - 'HPh' => 3.93015941224568E-04, - 'hh' => 3.93015941224568E-04, - 'Wh' => 2.93071851047526E-01, - 'wh' => 2.93071851047526E-01, - 'flb' => 2.50369750774671E+04, - 'BTU' => 1.0, - 'btu' => 1.0, - ], - 'btu' => [ - 'J' => 1.05505813786749E+03, - 'e' => 1.05505763074665E+10, - 'c' => 2.52165488508168E+02, - 'cal' => 2.51996617135510E+02, - 'eV' => 6.58510000000000E+21, - 'ev' => 6.58510000000000E+21, - 'HPh' => 3.93015941224568E-04, - 'hh' => 3.93015941224568E-04, - 'Wh' => 2.93071851047526E-01, - 'wh' => 2.93071851047526E-01, - 'flb' => 2.50369750774671E+04, - 'BTU' => 1.0, - 'btu' => 1.0, - ], - ], - 'Power' => [ - 'HP' => [ - 'HP' => 1.0, - 'h' => 1.0, - 'W' => 7.45701000000000E+02, - 'w' => 7.45701000000000E+02, - ], - 'h' => [ - 'HP' => 1.0, - 'h' => 1.0, - 'W' => 7.45701000000000E+02, - 'w' => 7.45701000000000E+02, - ], - 'W' => [ - 'HP' => 1.34102006031908E-03, - 'h' => 1.34102006031908E-03, - 'W' => 1.0, - 'w' => 1.0, - ], - 'w' => [ - 'HP' => 1.34102006031908E-03, - 'h' => 1.34102006031908E-03, - 'W' => 1.0, - 'w' => 1.0, - ], - ], - 'Magnetism' => [ - 'T' => [ - 'T' => 1.0, - 'ga' => 10000.0, - ], - 'ga' => [ - 'T' => 0.0001, - 'ga' => 1.0, - ], - ], - 'Liquid' => [ - 'tsp' => [ - 'tsp' => 1.0, - 'tbs' => 3.33333333333333E-01, - 'oz' => 1.66666666666667E-01, - 'cup' => 2.08333333333333E-02, - 'pt' => 1.04166666666667E-02, - 'us_pt' => 1.04166666666667E-02, - 'uk_pt' => 8.67558516821960E-03, - 'qt' => 5.20833333333333E-03, - 'gal' => 1.30208333333333E-03, - 'l' => 4.92999408400710E-03, - 'lt' => 4.92999408400710E-03, - ], - 'tbs' => [ - 'tsp' => 3.00000000000000E+00, - 'tbs' => 1.0, - 'oz' => 5.00000000000000E-01, - 'cup' => 6.25000000000000E-02, - 'pt' => 3.12500000000000E-02, - 'us_pt' => 3.12500000000000E-02, - 'uk_pt' => 2.60267555046588E-02, - 'qt' => 1.56250000000000E-02, - 'gal' => 3.90625000000000E-03, - 'l' => 1.47899822520213E-02, - 'lt' => 1.47899822520213E-02, - ], - 'oz' => [ - 'tsp' => 6.00000000000000E+00, - 'tbs' => 2.00000000000000E+00, - 'oz' => 1.0, - 'cup' => 1.25000000000000E-01, - 'pt' => 6.25000000000000E-02, - 'us_pt' => 6.25000000000000E-02, - 'uk_pt' => 5.20535110093176E-02, - 'qt' => 3.12500000000000E-02, - 'gal' => 7.81250000000000E-03, - 'l' => 2.95799645040426E-02, - 'lt' => 2.95799645040426E-02, - ], - 'cup' => [ - 'tsp' => 4.80000000000000E+01, - 'tbs' => 1.60000000000000E+01, - 'oz' => 8.00000000000000E+00, - 'cup' => 1.0, - 'pt' => 5.00000000000000E-01, - 'us_pt' => 5.00000000000000E-01, - 'uk_pt' => 4.16428088074541E-01, - 'qt' => 2.50000000000000E-01, - 'gal' => 6.25000000000000E-02, - 'l' => 2.36639716032341E-01, - 'lt' => 2.36639716032341E-01, - ], - 'pt' => [ - 'tsp' => 9.60000000000000E+01, - 'tbs' => 3.20000000000000E+01, - 'oz' => 1.60000000000000E+01, - 'cup' => 2.00000000000000E+00, - 'pt' => 1.0, - 'us_pt' => 1.0, - 'uk_pt' => 8.32856176149081E-01, - 'qt' => 5.00000000000000E-01, - 'gal' => 1.25000000000000E-01, - 'l' => 4.73279432064682E-01, - 'lt' => 4.73279432064682E-01, - ], - 'us_pt' => [ - 'tsp' => 9.60000000000000E+01, - 'tbs' => 3.20000000000000E+01, - 'oz' => 1.60000000000000E+01, - 'cup' => 2.00000000000000E+00, - 'pt' => 1.0, - 'us_pt' => 1.0, - 'uk_pt' => 8.32856176149081E-01, - 'qt' => 5.00000000000000E-01, - 'gal' => 1.25000000000000E-01, - 'l' => 4.73279432064682E-01, - 'lt' => 4.73279432064682E-01, - ], - 'uk_pt' => [ - 'tsp' => 1.15266000000000E+02, - 'tbs' => 3.84220000000000E+01, - 'oz' => 1.92110000000000E+01, - 'cup' => 2.40137500000000E+00, - 'pt' => 1.20068750000000E+00, - 'us_pt' => 1.20068750000000E+00, - 'uk_pt' => 1.0, - 'qt' => 6.00343750000000E-01, - 'gal' => 1.50085937500000E-01, - 'l' => 5.68260698087162E-01, - 'lt' => 5.68260698087162E-01, - ], - 'qt' => [ - 'tsp' => 1.92000000000000E+02, - 'tbs' => 6.40000000000000E+01, - 'oz' => 3.20000000000000E+01, - 'cup' => 4.00000000000000E+00, - 'pt' => 2.00000000000000E+00, - 'us_pt' => 2.00000000000000E+00, - 'uk_pt' => 1.66571235229816E+00, - 'qt' => 1.0, - 'gal' => 2.50000000000000E-01, - 'l' => 9.46558864129363E-01, - 'lt' => 9.46558864129363E-01, - ], - 'gal' => [ - 'tsp' => 7.68000000000000E+02, - 'tbs' => 2.56000000000000E+02, - 'oz' => 1.28000000000000E+02, - 'cup' => 1.60000000000000E+01, - 'pt' => 8.00000000000000E+00, - 'us_pt' => 8.00000000000000E+00, - 'uk_pt' => 6.66284940919265E+00, - 'qt' => 4.00000000000000E+00, - 'gal' => 1.0, - 'l' => 3.78623545651745E+00, - 'lt' => 3.78623545651745E+00, - ], - 'l' => [ - 'tsp' => 2.02840000000000E+02, - 'tbs' => 6.76133333333333E+01, - 'oz' => 3.38066666666667E+01, - 'cup' => 4.22583333333333E+00, - 'pt' => 2.11291666666667E+00, - 'us_pt' => 2.11291666666667E+00, - 'uk_pt' => 1.75975569552166E+00, - 'qt' => 1.05645833333333E+00, - 'gal' => 2.64114583333333E-01, - 'l' => 1.0, - 'lt' => 1.0, - ], - 'lt' => [ - 'tsp' => 2.02840000000000E+02, - 'tbs' => 6.76133333333333E+01, - 'oz' => 3.38066666666667E+01, - 'cup' => 4.22583333333333E+00, - 'pt' => 2.11291666666667E+00, - 'us_pt' => 2.11291666666667E+00, - 'uk_pt' => 1.75975569552166E+00, - 'qt' => 1.05645833333333E+00, - 'gal' => 2.64114583333333E-01, - 'l' => 1.0, - 'lt' => 1.0, - ], - ], - ]; - /** * parseComplex. * @@ -2585,69 +1882,68 @@ class Engineering * getConversionGroups * Returns a list of the different conversion groups for UOM conversions. * + * @Deprecated Use the getConversionCategories() method in the ConvertUOM class instead + * * @return array */ public static function getConversionGroups() { - $conversionGroups = []; - foreach (self::$conversionUnits as $conversionUnit) { - $conversionGroups[] = $conversionUnit['Group']; - } - - return array_merge(array_unique($conversionGroups)); + return Engineering\ConvertUOM::getConversionCategories(); } /** * getConversionGroupUnits * Returns an array of units of measure, for a specified conversion group, or for all groups. * - * @param string $group The group whose units of measure you want to retrieve + * @Deprecated Use the getConversionCategoryUnits() method in the ConvertUOM class instead + * + * @param null|mixed $category * * @return array */ - public static function getConversionGroupUnits($group = null) + public static function getConversionGroupUnits($category = null) { - $conversionGroups = []; - foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) { - if (($group === null) || ($conversionGroup['Group'] == $group)) { - $conversionGroups[$conversionGroup['Group']][] = $conversionUnit; - } - } - - return $conversionGroups; + return Engineering\ConvertUOM::getConversionCategoryUnits($category); } /** * getConversionGroupUnitDetails. * - * @param string $group The group whose units of measure you want to retrieve + * @Deprecated Use the getConversionCategoryUnitDetails() method in the ConvertUOM class instead + * + * @param null|mixed $category * * @return array */ - public static function getConversionGroupUnitDetails($group = null) + public static function getConversionGroupUnitDetails($category = null) { - $conversionGroups = []; - foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) { - if (($group === null) || ($conversionGroup['Group'] == $group)) { - $conversionGroups[$conversionGroup['Group']][] = [ - 'unit' => $conversionUnit, - 'description' => $conversionGroup['Unit Name'], - ]; - } - } - - return $conversionGroups; + return Engineering\ConvertUOM::getConversionCategoryUnitDetails($category); } /** * getConversionMultipliers * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). * + * @Deprecated Use the getConversionMultipliers() method in the ConvertUOM class instead + * * @return array of mixed */ public static function getConversionMultipliers() { - return self::$conversionMultipliers; + return Engineering\ConvertUOM::getConversionMultipliers(); + } + + /** + * getBinaryConversionMultipliers + * Returns an array of the additional Multiplier prefixes that can be used with Information Units of Measure in CONVERTUOM(). + * + * @Deprecated Use the getBinaryConversionMultipliers() method in the ConvertUOM class instead + * + * @return array of mixed + */ + public static function getBinaryConversionMultipliers() + { + return Engineering\ConvertUOM::getBinaryConversionMultipliers(); } /** @@ -2660,7 +1956,9 @@ class Engineering * Excel Function: * CONVERT(value,fromUOM,toUOM) * - * @param float $value the value in fromUOM to convert + * @Deprecated Use the CONVERT() method in the ConvertUOM class instead + * + * @param float|int $value the value in fromUOM to convert * @param string $fromUOM the units for value * @param string $toUOM the units for the result * @@ -2668,93 +1966,6 @@ class Engineering */ public static function CONVERTUOM($value, $fromUOM, $toUOM) { - $value = Functions::flattenSingleValue($value); - $fromUOM = Functions::flattenSingleValue($fromUOM); - $toUOM = Functions::flattenSingleValue($toUOM); - - if (!is_numeric($value)) { - return Functions::VALUE(); - } - $fromMultiplier = 1.0; - if (isset(self::$conversionUnits[$fromUOM])) { - $unitGroup1 = self::$conversionUnits[$fromUOM]['Group']; - } else { - $fromMultiplier = substr($fromUOM, 0, 1); - $fromUOM = substr($fromUOM, 1); - if (isset(self::$conversionMultipliers[$fromMultiplier])) { - $fromMultiplier = self::$conversionMultipliers[$fromMultiplier]['multiplier']; - } else { - return Functions::NA(); - } - if ((isset(self::$conversionUnits[$fromUOM])) && (self::$conversionUnits[$fromUOM]['AllowPrefix'])) { - $unitGroup1 = self::$conversionUnits[$fromUOM]['Group']; - } else { - return Functions::NA(); - } - } - $value *= $fromMultiplier; - - $toMultiplier = 1.0; - if (isset(self::$conversionUnits[$toUOM])) { - $unitGroup2 = self::$conversionUnits[$toUOM]['Group']; - } else { - $toMultiplier = substr($toUOM, 0, 1); - $toUOM = substr($toUOM, 1); - if (isset(self::$conversionMultipliers[$toMultiplier])) { - $toMultiplier = self::$conversionMultipliers[$toMultiplier]['multiplier']; - } else { - return Functions::NA(); - } - if ((isset(self::$conversionUnits[$toUOM])) && (self::$conversionUnits[$toUOM]['AllowPrefix'])) { - $unitGroup2 = self::$conversionUnits[$toUOM]['Group']; - } else { - return Functions::NA(); - } - } - if ($unitGroup1 != $unitGroup2) { - return Functions::NA(); - } - - if (($fromUOM == $toUOM) && ($fromMultiplier == $toMultiplier)) { - // We've already factored $fromMultiplier into the value, so we need - // to reverse it again - return $value / $fromMultiplier; - } elseif ($unitGroup1 == 'Temperature') { - if (($fromUOM == 'F') || ($fromUOM == 'fah')) { - if (($toUOM == 'F') || ($toUOM == 'fah')) { - return $value; - } - $value = (($value - 32) / 1.8); - if (($toUOM == 'K') || ($toUOM == 'kel')) { - $value += 273.15; - } - - return $value; - } elseif ( - (($fromUOM == 'K') || ($fromUOM == 'kel')) && - (($toUOM == 'K') || ($toUOM == 'kel')) - ) { - return $value; - } elseif ( - (($fromUOM == 'C') || ($fromUOM == 'cel')) && - (($toUOM == 'C') || ($toUOM == 'cel')) - ) { - return $value; - } - if (($toUOM == 'F') || ($toUOM == 'fah')) { - if (($fromUOM == 'K') || ($fromUOM == 'kel')) { - $value -= 273.15; - } - - return ($value * 1.8) + 32; - } - if (($toUOM == 'C') || ($toUOM == 'cel')) { - return $value - 273.15; - } - - return $value + 273.15; - } - - return ($value * self::$unitConversions[$unitGroup1][$fromUOM][$toUOM]) / $toMultiplier; + return Engineering\ConvertUOM::CONVERT($value, $fromUOM, $toUOM); } } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php new file mode 100644 index 00000000..0aafe05e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php @@ -0,0 +1,684 @@ + ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Gram', 'AllowPrefix' => true], + 'sg' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Slug', 'AllowPrefix' => false], + 'lbm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Pound mass (avoirdupois)', 'AllowPrefix' => false], + 'u' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'U (atomic mass unit)', 'AllowPrefix' => true], + 'ozm' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Ounce mass (avoirdupois)', 'AllowPrefix' => false], + 'grain' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Grain', 'AllowPrefix' => false], + 'cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'U.S. (short) hundredweight', 'AllowPrefix' => false], + 'shweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'U.S. (short) hundredweight', 'AllowPrefix' => false], + 'uk_cwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial hundredweight', 'AllowPrefix' => false], + 'lcwt' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial hundredweight', 'AllowPrefix' => false], + 'hweight' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial hundredweight', 'AllowPrefix' => false], + 'stone' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Stone', 'AllowPrefix' => false], + 'ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Ton', 'AllowPrefix' => false], + 'uk_ton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial ton', 'AllowPrefix' => false], + 'LTON' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial ton', 'AllowPrefix' => false], + 'brton' => ['Group' => self::CATEGORY_WEIGHT_AND_MASS, 'Unit Name' => 'Imperial ton', 'AllowPrefix' => false], + // Distance + 'm' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Meter', 'AllowPrefix' => true], + 'mi' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Statute mile', 'AllowPrefix' => false], + 'Nmi' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Nautical mile', 'AllowPrefix' => false], + 'in' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Inch', 'AllowPrefix' => false], + 'ft' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Foot', 'AllowPrefix' => false], + 'yd' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Yard', 'AllowPrefix' => false], + 'ang' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Angstrom', 'AllowPrefix' => true], + 'ell' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Ell', 'AllowPrefix' => false], + 'ly' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Light Year', 'AllowPrefix' => false], + 'parsec' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Parsec', 'AllowPrefix' => false], + 'pc' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Parsec', 'AllowPrefix' => false], + 'Pica' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false], + 'Picapt' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Pica (1/72 in)', 'AllowPrefix' => false], + 'pica' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'Pica (1/6 in)', 'AllowPrefix' => false], + 'survey_mi' => ['Group' => self::CATEGORY_DISTANCE, 'Unit Name' => 'U.S survey mile (statute mile)', 'AllowPrefix' => false], + // Time + 'yr' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Year', 'AllowPrefix' => false], + 'day' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Day', 'AllowPrefix' => false], + 'd' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Day', 'AllowPrefix' => false], + 'hr' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Hour', 'AllowPrefix' => false], + 'mn' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Minute', 'AllowPrefix' => false], + 'min' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Minute', 'AllowPrefix' => false], + 'sec' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Second', 'AllowPrefix' => true], + 's' => ['Group' => self::CATEGORY_TIME, 'Unit Name' => 'Second', 'AllowPrefix' => true], + // Pressure + 'Pa' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Pascal', 'AllowPrefix' => true], + 'p' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Pascal', 'AllowPrefix' => true], + 'atm' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true], + 'at' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Atmosphere', 'AllowPrefix' => true], + 'mmHg' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'mm of Mercury', 'AllowPrefix' => true], + 'psi' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'PSI', 'AllowPrefix' => true], + 'Torr' => ['Group' => self::CATEGORY_PRESSURE, 'Unit Name' => 'Torr', 'AllowPrefix' => true], + // Force + 'N' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Newton', 'AllowPrefix' => true], + 'dyn' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Dyne', 'AllowPrefix' => true], + 'dy' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Dyne', 'AllowPrefix' => true], + 'lbf' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Pound force', 'AllowPrefix' => false], + 'pond' => ['Group' => self::CATEGORY_FORCE, 'Unit Name' => 'Pond', 'AllowPrefix' => true], + // Energy + 'J' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Joule', 'AllowPrefix' => true], + 'e' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Erg', 'AllowPrefix' => true], + 'c' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Thermodynamic calorie', 'AllowPrefix' => true], + 'cal' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'IT calorie', 'AllowPrefix' => true], + 'eV' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Electron volt', 'AllowPrefix' => true], + 'ev' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Electron volt', 'AllowPrefix' => true], + 'HPh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false], + 'hh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Horsepower-hour', 'AllowPrefix' => false], + 'Wh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true], + 'wh' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Watt-hour', 'AllowPrefix' => true], + 'flb' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'Foot-pound', 'AllowPrefix' => false], + 'BTU' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'BTU', 'AllowPrefix' => false], + 'btu' => ['Group' => self::CATEGORY_ENERGY, 'Unit Name' => 'BTU', 'AllowPrefix' => false], + // Power + 'HP' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Horsepower', 'AllowPrefix' => false], + 'h' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Horsepower', 'AllowPrefix' => false], + 'W' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Watt', 'AllowPrefix' => true], + 'w' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Watt', 'AllowPrefix' => true], + 'PS' => ['Group' => self::CATEGORY_POWER, 'Unit Name' => 'Pferdestärke', 'AllowPrefix' => false], + 'T' => ['Group' => self::CATEGORY_MAGNETISM, 'Unit Name' => 'Tesla', 'AllowPrefix' => true], + 'ga' => ['Group' => self::CATEGORY_MAGNETISM, 'Unit Name' => 'Gauss', 'AllowPrefix' => true], + // Temperature + 'C' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Celsius', 'AllowPrefix' => false], + 'cel' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Celsius', 'AllowPrefix' => false], + 'F' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Fahrenheit', 'AllowPrefix' => false], + 'fah' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Fahrenheit', 'AllowPrefix' => false], + 'K' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Kelvin', 'AllowPrefix' => false], + 'kel' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Kelvin', 'AllowPrefix' => false], + 'Rank' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Rankine', 'AllowPrefix' => false], + 'Reau' => ['Group' => self::CATEGORY_TEMPERATURE, 'Unit Name' => 'Degrees Réaumur', 'AllowPrefix' => false], + // Volume + 'l' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Litre', 'AllowPrefix' => true], + 'L' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Litre', 'AllowPrefix' => true], + 'lt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Litre', 'AllowPrefix' => true], + 'tsp' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Teaspoon', 'AllowPrefix' => false], + 'tspm' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Modern Teaspoon', 'AllowPrefix' => false], + 'tbs' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Tablespoon', 'AllowPrefix' => false], + 'oz' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Fluid Ounce', 'AllowPrefix' => false], + 'cup' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cup', 'AllowPrefix' => false], + 'pt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false], + 'us_pt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'U.S. Pint', 'AllowPrefix' => false], + 'uk_pt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'U.K. Pint', 'AllowPrefix' => false], + 'qt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Quart', 'AllowPrefix' => false], + 'uk_qt' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Imperial Quart (UK)', 'AllowPrefix' => false], + 'gal' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Gallon', 'AllowPrefix' => false], + 'uk_gal' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Imperial Gallon (UK)', 'AllowPrefix' => false], + 'ang3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Angstrom', 'AllowPrefix' => true], + 'ang^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Angstrom', 'AllowPrefix' => true], + 'barrel' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'US Oil Barrel', 'AllowPrefix' => false], + 'bushel' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'US Bushel', 'AllowPrefix' => false], + 'in3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Inch', 'AllowPrefix' => false], + 'in^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Inch', 'AllowPrefix' => false], + 'ft3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Foot', 'AllowPrefix' => false], + 'ft^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Foot', 'AllowPrefix' => false], + 'ly3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Light Year', 'AllowPrefix' => false], + 'ly^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Light Year', 'AllowPrefix' => false], + 'm3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Meter', 'AllowPrefix' => true], + 'm^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Meter', 'AllowPrefix' => true], + 'mi3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Mile', 'AllowPrefix' => false], + 'mi^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Mile', 'AllowPrefix' => false], + 'yd3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Yard', 'AllowPrefix' => false], + 'yd^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Yard', 'AllowPrefix' => false], + 'Nmi3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Nautical Mile', 'AllowPrefix' => false], + 'Nmi^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Nautical Mile', 'AllowPrefix' => false], + 'Pica3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], + 'Pica^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], + 'Picapt3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], + 'Picapt^3' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Cubic Pica', 'AllowPrefix' => false], + 'GRT' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Gross Registered Ton', 'AllowPrefix' => false], + 'regton' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Gross Registered Ton', 'AllowPrefix' => false], + 'MTON' => ['Group' => self::CATEGORY_VOLUME, 'Unit Name' => 'Measurement Ton (Freight Ton)', 'AllowPrefix' => false], + // Area + 'ha' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Hectare', 'AllowPrefix' => true], + 'uk_acre' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'International Acre', 'AllowPrefix' => false], + 'us_acre' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'US Survey/Statute Acre', 'AllowPrefix' => false], + 'ang2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Angstrom', 'AllowPrefix' => true], + 'ang^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Angstrom', 'AllowPrefix' => true], + 'ar' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Are', 'AllowPrefix' => true], + 'ft2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Feet', 'AllowPrefix' => false], + 'ft^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Feet', 'AllowPrefix' => false], + 'in2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Inches', 'AllowPrefix' => false], + 'in^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Inches', 'AllowPrefix' => false], + 'ly2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Light Years', 'AllowPrefix' => false], + 'ly^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Light Years', 'AllowPrefix' => false], + 'm2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Meters', 'AllowPrefix' => true], + 'm^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Meters', 'AllowPrefix' => true], + 'Morgen' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Morgen', 'AllowPrefix' => false], + 'mi2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Miles', 'AllowPrefix' => false], + 'mi^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Miles', 'AllowPrefix' => false], + 'Nmi2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Nautical Miles', 'AllowPrefix' => false], + 'Nmi^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Nautical Miles', 'AllowPrefix' => false], + 'Pica2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], + 'Pica^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], + 'Picapt2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], + 'Picapt^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Pica', 'AllowPrefix' => false], + 'yd2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Yards', 'AllowPrefix' => false], + 'yd^2' => ['Group' => self::CATEGORY_AREA, 'Unit Name' => 'Square Yards', 'AllowPrefix' => false], + // Information + 'byte' => ['Group' => self::CATEGORY_INFORMATION, 'Unit Name' => 'Byte', 'AllowPrefix' => true], + 'bit' => ['Group' => self::CATEGORY_INFORMATION, 'Unit Name' => 'Bit', 'AllowPrefix' => true], + // Speed + 'm/s' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per second', 'AllowPrefix' => true], + 'm/sec' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per second', 'AllowPrefix' => true], + 'm/h' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per hour', 'AllowPrefix' => true], + 'm/hr' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Meters per hour', 'AllowPrefix' => true], + 'mph' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Miles per hour', 'AllowPrefix' => false], + 'admkn' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Admiralty Knot', 'AllowPrefix' => false], + 'kn' => ['Group' => self::CATEGORY_SPEED, 'Unit Name' => 'Knot', 'AllowPrefix' => false], + ]; + + /** + * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). + * + * @var mixed[] + */ + private static $conversionMultipliers = [ + 'Y' => ['multiplier' => 1E24, 'name' => 'yotta'], + 'Z' => ['multiplier' => 1E21, 'name' => 'zetta'], + 'E' => ['multiplier' => 1E18, 'name' => 'exa'], + 'P' => ['multiplier' => 1E15, 'name' => 'peta'], + 'T' => ['multiplier' => 1E12, 'name' => 'tera'], + 'G' => ['multiplier' => 1E9, 'name' => 'giga'], + 'M' => ['multiplier' => 1E6, 'name' => 'mega'], + 'k' => ['multiplier' => 1E3, 'name' => 'kilo'], + 'h' => ['multiplier' => 1E2, 'name' => 'hecto'], + 'e' => ['multiplier' => 1E1, 'name' => 'dekao'], + 'da' => ['multiplier' => 1E1, 'name' => 'dekao'], + 'd' => ['multiplier' => 1E-1, 'name' => 'deci'], + 'c' => ['multiplier' => 1E-2, 'name' => 'centi'], + 'm' => ['multiplier' => 1E-3, 'name' => 'milli'], + 'u' => ['multiplier' => 1E-6, 'name' => 'micro'], + 'n' => ['multiplier' => 1E-9, 'name' => 'nano'], + 'p' => ['multiplier' => 1E-12, 'name' => 'pico'], + 'f' => ['multiplier' => 1E-15, 'name' => 'femto'], + 'a' => ['multiplier' => 1E-18, 'name' => 'atto'], + 'z' => ['multiplier' => 1E-21, 'name' => 'zepto'], + 'y' => ['multiplier' => 1E-24, 'name' => 'yocto'], + ]; + + /** + * Details of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). + * + * @var mixed[] + */ + private static $binaryConversionMultipliers = [ + 'Yi' => ['multiplier' => 2 ** 80, 'name' => 'yobi'], + 'Zi' => ['multiplier' => 2 ** 70, 'name' => 'zebi'], + 'Ei' => ['multiplier' => 2 ** 60, 'name' => 'exbi'], + 'Pi' => ['multiplier' => 2 ** 50, 'name' => 'pebi'], + 'Ti' => ['multiplier' => 2 ** 40, 'name' => 'tebi'], + 'Gi' => ['multiplier' => 2 ** 30, 'name' => 'gibi'], + 'Mi' => ['multiplier' => 2 ** 20, 'name' => 'mebi'], + 'ki' => ['multiplier' => 2 ** 10, 'name' => 'kibi'], + ]; + + /** + * Details of the Units of measure conversion factors, organised by group. + * + * @var mixed[] + */ + private static $unitConversions = [ + // Conversion uses gram (g) as an intermediate unit + self::CATEGORY_WEIGHT_AND_MASS => [ + 'g' => 1.0, + 'sg' => 6.85217658567918E-05, + 'lbm' => 2.20462262184878E-03, + 'u' => 6.02214179421676E+23, + 'ozm' => 3.52739619495804E-02, + 'grain' => 1.54323583529414E+01, + 'cwt' => 2.20462262184878E-05, + 'shweight' => 2.20462262184878E-05, + 'uk_cwt' => 1.96841305522212E-05, + 'lcwt' => 1.96841305522212E-05, + 'hweight' => 1.96841305522212E-05, + 'stone' => 1.57473044417770E-04, + 'ton' => 1.10231131092439E-06, + 'uk_ton' => 9.84206527611061E-07, + 'LTON' => 9.84206527611061E-07, + 'brton' => 9.84206527611061E-07, + ], + // Conversion uses meter (m) as an intermediate unit + self::CATEGORY_DISTANCE => [ + 'm' => 1.0, + 'mi' => 6.21371192237334E-04, + 'Nmi' => 5.39956803455724E-04, + 'in' => 3.93700787401575E+01, + 'ft' => 3.28083989501312E+00, + 'yd' => 1.09361329833771E+00, + 'ang' => 1.0E+10, + 'ell' => 8.74890638670166E-01, + 'ly' => 1.05700083402462E-16, + 'parsec' => 3.24077928966473E-17, + 'pc' => 3.24077928966473E-17, + 'Pica' => 2.83464566929134E+03, + 'Picapt' => 2.83464566929134E+03, + 'pica' => 2.36220472440945E+02, + 'survey_mi' => 6.21369949494950E-04, + ], + // Conversion uses second (s) as an intermediate unit + self::CATEGORY_TIME => [ + 'yr' => 3.16880878140289E-08, + 'day' => 1.15740740740741E-05, + 'd' => 1.15740740740741E-05, + 'hr' => 2.77777777777778E-04, + 'mn' => 1.66666666666667E-02, + 'min' => 1.66666666666667E-02, + 'sec' => 1.0, + 's' => 1.0, + ], + // Conversion uses Pascal (Pa) as an intermediate unit + self::CATEGORY_PRESSURE => [ + 'Pa' => 1.0, + 'p' => 1.0, + 'atm' => 9.86923266716013E-06, + 'at' => 9.86923266716013E-06, + 'mmHg' => 7.50063755419211E-03, + 'psi' => 1.45037737730209E-04, + 'Torr' => 7.50061682704170E-03, + ], + // Conversion uses Newton (N) as an intermediate unit + self::CATEGORY_FORCE => [ + 'N' => 1.0, + 'dyn' => 1.0E+5, + 'dy' => 1.0E+5, + 'lbf' => 2.24808923655339E-01, + 'pond' => 1.01971621297793E+02, + ], + // Conversion uses Joule (J) as an intermediate unit + self::CATEGORY_ENERGY => [ + 'J' => 1.0, + 'e' => 9.99999519343231E+06, + 'c' => 2.39006249473467E-01, + 'cal' => 2.38846190642017E-01, + 'eV' => 6.24145700000000E+18, + 'ev' => 6.24145700000000E+18, + 'HPh' => 3.72506430801000E-07, + 'hh' => 3.72506430801000E-07, + 'Wh' => 2.77777916238711E-04, + 'wh' => 2.77777916238711E-04, + 'flb' => 2.37304222192651E+01, + 'BTU' => 9.47815067349015E-04, + 'btu' => 9.47815067349015E-04, + ], + // Conversion uses Horsepower (HP) as an intermediate unit + self::CATEGORY_POWER => [ + 'HP' => 1.0, + 'h' => 1.0, + 'W' => 7.45699871582270E+02, + 'w' => 7.45699871582270E+02, + 'PS' => 1.01386966542400E+00, + ], + // Conversion uses Tesla (T) as an intermediate unit + self::CATEGORY_MAGNETISM => [ + 'T' => 1.0, + 'ga' => 10000.0, + ], + // Conversion uses litre (l) as an intermediate unit + self::CATEGORY_VOLUME => [ + 'l' => 1.0, + 'L' => 1.0, + 'lt' => 1.0, + 'tsp' => 2.02884136211058E+02, + 'tspm' => 2.0E+02, + 'tbs' => 6.76280454036860E+01, + 'oz' => 3.38140227018430E+01, + 'cup' => 4.22675283773038E+00, + 'pt' => 2.11337641886519E+00, + 'us_pt' => 2.11337641886519E+00, + 'uk_pt' => 1.75975398639270E+00, + 'qt' => 1.05668820943259E+00, + 'uk_qt' => 8.79876993196351E-01, + 'gal' => 2.64172052358148E-01, + 'uk_gal' => 2.19969248299088E-01, + 'ang3' => 1.0E+27, + 'ang^3' => 1.0E+27, + 'barrel' => 6.28981077043211E-03, + 'bushel' => 2.83775932584017E-02, + 'in3' => 6.10237440947323E+01, + 'in^3' => 6.10237440947323E+01, + 'ft3' => 3.53146667214886E-02, + 'ft^3' => 3.53146667214886E-02, + 'ly3' => 1.18093498844171E-51, + 'ly^3' => 1.18093498844171E-51, + 'm3' => 1.0E-03, + 'm^3' => 1.0E-03, + 'mi3' => 2.39912758578928E-13, + 'mi^3' => 2.39912758578928E-13, + 'yd3' => 1.30795061931439E-03, + 'yd^3' => 1.30795061931439E-03, + 'Nmi3' => 1.57426214685811E-13, + 'Nmi^3' => 1.57426214685811E-13, + 'Pica3' => 2.27769904358706E+07, + 'Pica^3' => 2.27769904358706E+07, + 'Picapt3' => 2.27769904358706E+07, + 'Picapt^3' => 2.27769904358706E+07, + 'GRT' => 3.53146667214886E-04, + 'regton' => 3.53146667214886E-04, + 'MTON' => 8.82866668037215E-04, + ], + // Conversion uses hectare (ha) as an intermediate unit + self::CATEGORY_AREA => [ + 'ha' => 1.0, + 'uk_acre' => 2.47105381467165E+00, + 'us_acre' => 2.47104393046628E+00, + 'ang2' => 1.0E+24, + 'ang^2' => 1.0E+24, + 'ar' => 1.0E+02, + 'ft2' => 1.07639104167097E+05, + 'ft^2' => 1.07639104167097E+05, + 'in2' => 1.55000310000620E+07, + 'in^2' => 1.55000310000620E+07, + 'ly2' => 1.11725076312873E-28, + 'ly^2' => 1.11725076312873E-28, + 'm2' => 1.0E+04, + 'm^2' => 1.0E+04, + 'Morgen' => 4.0E+00, + 'mi2' => 3.86102158542446E-03, + 'mi^2' => 3.86102158542446E-03, + 'Nmi2' => 2.91553349598123E-03, + 'Nmi^2' => 2.91553349598123E-03, + 'Pica2' => 8.03521607043214E+10, + 'Pica^2' => 8.03521607043214E+10, + 'Picapt2' => 8.03521607043214E+10, + 'Picapt^2' => 8.03521607043214E+10, + 'yd2' => 1.19599004630108E+04, + 'yd^2' => 1.19599004630108E+04, + ], + // Conversion uses bit (bit) as an intermediate unit + self::CATEGORY_INFORMATION => [ + 'bit' => 1.0, + 'byte' => 0.125, + ], + // Conversion uses Meters per Second (m/s) as an intermediate unit + self::CATEGORY_SPEED => [ + 'm/s' => 1.0, + 'm/sec' => 1.0, + 'm/h' => 3.60E+03, + 'm/hr' => 3.60E+03, + 'mph' => 2.23693629205440E+00, + 'admkn' => 1.94260256941567E+00, + 'kn' => 1.94384449244060E+00, + ], + ]; + + /** + * getConversionGroups + * Returns a list of the different conversion groups for UOM conversions. + * + * @return array + */ + public static function getConversionCategories() + { + $conversionGroups = []; + foreach (self::$conversionUnits as $conversionUnit) { + $conversionGroups[] = $conversionUnit['Group']; + } + + return array_merge(array_unique($conversionGroups)); + } + + /** + * getConversionGroupUnits + * Returns an array of units of measure, for a specified conversion group, or for all groups. + * + * @param string $category The group whose units of measure you want to retrieve + * + * @return array + */ + public static function getConversionCategoryUnits($category = null) + { + $conversionGroups = []; + foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) { + if (($category === null) || ($conversionGroup['Group'] == $category)) { + $conversionGroups[$conversionGroup['Group']][] = $conversionUnit; + } + } + + return $conversionGroups; + } + + /** + * getConversionGroupUnitDetails. + * + * @param string $category The group whose units of measure you want to retrieve + * + * @return array + */ + public static function getConversionCategoryUnitDetails($category = null) + { + $conversionGroups = []; + foreach (self::$conversionUnits as $conversionUnit => $conversionGroup) { + if (($category === null) || ($conversionGroup['Group'] == $category)) { + $conversionGroups[$conversionGroup['Group']][] = [ + 'unit' => $conversionUnit, + 'description' => $conversionGroup['Unit Name'], + ]; + } + } + + return $conversionGroups; + } + + /** + * getConversionMultipliers + * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). + * + * @return array of mixed + */ + public static function getConversionMultipliers() + { + return self::$conversionMultipliers; + } + + /** + * getBinaryConversionMultipliers + * Returns an array of the additional Multiplier prefixes that can be used with Information Units of Measure in CONVERTUOM(). + * + * @return array of mixed + */ + public static function getBinaryConversionMultipliers() + { + return self::$binaryConversionMultipliers; + } + + /** + * CONVERT. + * + * Converts a number from one measurement system to another. + * For example, CONVERT can translate a table of distances in miles to a table of distances + * in kilometers. + * + * Excel Function: + * CONVERT(value,fromUOM,toUOM) + * + * @param float|int $value the value in fromUOM to convert + * @param string $fromUOM the units for value + * @param string $toUOM the units for the result + * + * @return float|string + */ + public static function CONVERT($value, $fromUOM, $toUOM) + { + $value = Functions::flattenSingleValue($value); + $fromUOM = Functions::flattenSingleValue($fromUOM); + $toUOM = Functions::flattenSingleValue($toUOM); + + if (!is_numeric($value)) { + return Functions::VALUE(); + } + + try { + [$fromUOM, $fromCategory, $fromMultiplier] = self::getUOMDetails($fromUOM); + [$toUOM, $toCategory, $toMultiplier] = self::getUOMDetails($toUOM); + } catch (Exception $e) { + return Functions::NA(); + } + + if ($fromCategory !== $toCategory) { + return Functions::NA(); + } + + $value *= $fromMultiplier; + + if (($fromUOM === $toUOM) && ($fromMultiplier === $toMultiplier)) { + // We've already factored $fromMultiplier into the value, so we need + // to reverse it again + return $value / $fromMultiplier; + } elseif ($fromUOM === $toUOM) { + return $value / $toMultiplier; + } elseif ($fromCategory === self::CATEGORY_TEMPERATURE) { + return self::convertTemperature($fromUOM, $toUOM, $value); + } + + $baseValue = $value * (1.0 / self::$unitConversions[$fromCategory][$fromUOM]); + + return ($baseValue * self::$unitConversions[$fromCategory][$toUOM]) / $toMultiplier; + } + + private static function getUOMDetails(string $uom) + { + if (isset(self::$conversionUnits[$uom])) { + $unitCategory = self::$conversionUnits[$uom]['Group']; + + return [$uom, $unitCategory, 1.0]; + } + + // Check 1-character standard metric multiplier prefixes + $multiplierType = substr($uom, 0, 1); + $uom = substr($uom, 1); + if (isset(self::$conversionUnits[$uom], self::$conversionMultipliers[$multiplierType])) { + if (self::$conversionUnits[$uom]['AllowPrefix'] === false) { + throw new Exception('Prefix not allowed for UoM'); + } + $unitCategory = self::$conversionUnits[$uom]['Group']; + + return [$uom, $unitCategory, self::$conversionMultipliers[$multiplierType]['multiplier']]; + } + + $multiplierType .= substr($uom, 0, 1); + $uom = substr($uom, 1); + + // Check 2-character standard metric multiplier prefixes + if (isset(self::$conversionUnits[$uom], self::$conversionMultipliers[$multiplierType])) { + if (self::$conversionUnits[$uom]['AllowPrefix'] === false) { + throw new Exception('Prefix not allowed for UoM'); + } + $unitCategory = self::$conversionUnits[$uom]['Group']; + + return [$uom, $unitCategory, self::$conversionMultipliers[$multiplierType]['multiplier']]; + } + + // Check 2-character binary multiplier prefixes + if (isset(self::$conversionUnits[$uom], self::$binaryConversionMultipliers[$multiplierType])) { + if (self::$conversionUnits[$uom]['AllowPrefix'] === false) { + throw new Exception('Prefix not allowed for UoM'); + } + $unitCategory = self::$conversionUnits[$uom]['Group']; + if ($unitCategory !== 'Information') { + throw new Exception('Binary Prefix is only allowed for Information UoM'); + } + + return [$uom, $unitCategory, self::$binaryConversionMultipliers[$multiplierType]['multiplier']]; + } + + throw new Exception('UoM Not Found'); + } + + /** + * @param float|int $value + * + * @return float|int + */ + protected static function convertTemperature(string $fromUOM, string $toUOM, $value) + { + $fromUOM = self::resolveTemperatureSynonyms($fromUOM); + $toUOM = self::resolveTemperatureSynonyms($toUOM); + + if ($fromUOM === $toUOM) { + return $value; + } + + // Convert to Kelvin + switch ($fromUOM) { + case 'F': + $value = ($value - 32) / 1.8 + 273.15; + + break; + case 'C': + $value += 273.15; + + break; + case 'Rank': + $value /= 1.8; + + break; + case 'Reau': + $value = $value * 1.25 + 273.15; + + break; + } + + // Convert from Kelvin + switch ($toUOM) { + case 'F': + $value = ($value - 273.15) * 1.8 + 32.00; + + break; + case 'C': + $value -= 273.15; + + break; + case 'Rank': + $value *= 1.8; + + break; + case 'Reau': + $value = ($value - 273.15) * 0.80000; + + break; + } + + return $value; + } + + private static function resolveTemperatureSynonyms(string $uom) + { + switch ($uom) { + case 'fah': + return 'F'; + case 'cel': + return 'C'; + case 'kel': + return 'K'; + } + + return $uom; + } +} diff --git a/tests/data/Calculation/Engineering/CONVERTUOM.php b/tests/data/Calculation/Engineering/CONVERTUOM.php index 248c2cd0..64aaef62 100644 --- a/tests/data/Calculation/Engineering/CONVERTUOM.php +++ b/tests/data/Calculation/Engineering/CONVERTUOM.php @@ -1,18 +1,72 @@ [ + 1.942559385723E-03, + 1.0, + 'ozm', + 'sg', + ], + 'Same prefixed metric UoM' => [ + 5.0, + 5.0, + 'kg', + 'kg', + ], + 'Imperial to prefixed metric' => [ + 4.5359237E-01, 1.0, 'lbm', 'kg', ], - [ - 123.45, - 123.45, - 'kg', + 'Prefixed metric to prefixed metric, same unit' => [ + 0.2, + 2.0, + 'hg', 'kg', ], + 'Unprefixed metric to prefixed metric, same unit' => [ + 12.345000000000001, + 12345, + 'm', + 'km', + ], + 'Prefixed metric to unprefixed metric, same unit' => [ + 12345, + 12.345000000000001, + 'km', + 'm', + ], + 'Prefixed metric to imperial' => [ + 0.62137119223732995, + 1, + 'km', + 'mi', + ], + 'Prefixed metric to alternative metric' => [ + 1.23450000000000E+05, + 12.345, + 'um', + 'ang', + ], + 'Prefixed metric to alternative prefixed metric' => [ + 1.23450000000000E+02, + 12.345, + 'um', + 'kang', + ], + 'Prefixed metric to 2-character prefixed metric, same unit' => [ + 1000.0, + 100.0, + 'hl', + 'dal', + ], + 'Imperial to Imperial (distance)' => [ + 1.0, + 3.0, + 'ft', + 'yd', + ], [ 20, 68, @@ -38,111 +92,129 @@ return [ 'F', ], [ - 295.14999999999998, + -273.15, + 0, + 'K', + 'C', + ], + [ + -459.67, + 0, + 'K', + 'F', + ], + [ + 295.15, 22, 'C', 'K', ], [ 22.5, - 295.64999999999998, + 295.65, 'K', 'C', ], - [ - '#N/A', - 2.5, - 'ft', - 'sec', + 'Melting Point of Titanium (K to C)' => [ + 1667.85, + 1941, + 'K', + 'C', ], - [ - 12.345000000000001, - 12345, - 'm', - 'km', + 'Melting Point of Titanium (K to F)' => [ + 3034.13, + 1941, + 'K', + 'F', ], - [ - 12345, - 12.345000000000001, - 'km', - 'm', + 'Melting Point of Titanium (K to Rankine)' => [ + 3493.8, + 1941, + 'K', + 'Rank', ], - [ - 0.62137119223732995, - 1, - 'km', - 'mi', + 'Melting Point of Titanium (K to Réaumur)' => [ + 1334.28, + 1941, + 'K', + 'Reau', ], - [ - '#VALUE!', - 'three', - 'ft', - 'yds', - ], - [ + 'Temperature synonyms (K)' => [ 123.45, 123.45, 'K', 'kel', ], - [ + 'Temperature synonyms (C)' => [ 123.45, 123.45, 'C', 'cel', ], - [ + 'Temperature synonyms (F)' => [ 123.45, 123.45, 'F', 'fah', ], - [ + 'Invalid value to conver' => [ + '#VALUE!', + 'three', + 'ft', + 'yds', + ], + 'Prefixed metric to binary prefixed metric' => [ + '#N/A', + 12.345, + 'um', + 'kiang', + ], + 'Mismatched categories' => [ '#N/A', 1, 'ft', 'day', ], - [ - 123.45, - 123.45, - 'm', - 'm', - ], - [ - 234.56, - 234.56, - 'km', - 'km', - ], - [ + 'From Prefixed imperial (Invalid)' => [ '#N/A', 234.56, 'kpt', 'lt', ], - [ - '#N/A', - 234.56, - 'sm', - 'm', - ], - [ + 'To prefixed imperial (Invalid)' => [ '#N/A', 234.56, 'lt', 'kpt', ], - [ + 'Invalid from unit' => [ + '#N/A', + 234.56, + 'xxxx', + 'm', + ], + 'Invalid to unit' => [ '#N/A', 234.56, 'm', - 'sm', + 'xxxx', ], - [ - 12345000, - 12.345000000000001, - 'km', - 'mm', + 'Basic Information conversion' => [ + 2, + 16, + 'bit', + 'byte', + ], + 'Information with standard metric prefix' => [ + 1000, + 1, + 'kbyte', + 'byte', + ], + 'Information with binary prefix' => [ + 1024, + 1, + 'kibyte', + 'byte', ], ]; From 76d4323b85129d0c368149c831a07a3e258b2b50 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Thu, 31 Dec 2020 19:03:49 +0100 Subject: [PATCH 003/187] Changelog for 1.16.0 release --- CHANGELOG.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e37e66..a4741afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.16.0 - 2020-12-31 + +### Added + - CSV Reader - Best Guess for Encoding, and Handle Null-string Escape [#1647](https://github.com/PHPOffice/PhpSpreadsheet/issues/1647) ### Changed @@ -26,20 +48,20 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed - Fix for Xls Reader when SST has a bad length [#1592](https://github.com/PHPOffice/PhpSpreadsheet/issues/1592) -- Resolve Xlsx loader issue whe hyperlinks don't have a destination +- Resolve Xlsx loader issue whe hyperlinks don't have a destination - Resolve issues when printer settings resources IDs clash with drawing IDs - Resolve issue with SLK long filenames [#1612](https://github.com/PHPOffice/PhpSpreadsheet/issues/1612) - ROUNDUP and ROUNDDOWN return incorrect results for values of 0 [#1627](https://github.com/phpoffice/phpspreadsheet/pull/1627) - Apply Column and Row Styles to Existing Cells [#1712](https://github.com/PHPOffice/PhpSpreadsheet/issues/1712) [PR #1721](https://github.com/PHPOffice/PhpSpreadsheet/pull/1721) - Resolve issues with defined names where worksheet doesn't exist (#1686)[https://github.com/PHPOffice/PhpSpreadsheet/issues/1686] and [#1723](https://github.com/PHPOffice/PhpSpreadsheet/issues/1723) - [PR #1742](https://github.com/PHPOffice/PhpSpreadsheet/pull/1742) -- Fix for issue [#1735](https://github.com/PHPOffice/PhpSpreadsheet/issues/1735) Incorrect activeSheetIndex after RemoveSheetByIndex - [PR #1743](https://github.com/PHPOffice/PhpSpreadsheet/pull/1743) +- Fix for issue [#1735](https://github.com/PHPOffice/PhpSpreadsheet/issues/1735) Incorrect activeSheetIndex after RemoveSheetByIndex - [PR #1743](https://github.com/PHPOffice/PhpSpreadsheet/pull/1743) - Ensure that the list of shared formulae is maintained when an xlsx file is chunked with readFilter[Issue #169](https://github.com/PHPOffice/PhpSpreadsheet/issues/1669). - Fix for notice during accessing "cached magnification factor" offset [#1354](https://github.com/PHPOffice/PhpSpreadsheet/pull/1354) - Fix compatibility with ext-gd on php 8 ### Security Fix (CVE-2020-7776) -- Prevent XSS through cell comments in the HTML Writer. +- Prevent XSS through cell comments in the HTML Writer. ## 1.15.0 - 2020-10-11 From d2edab2827b4255878def0c8c6833f56d5a73aa2 Mon Sep 17 00:00:00 2001 From: Martins Sipenko Date: Thu, 7 Jan 2021 12:41:46 +0200 Subject: [PATCH 004/187] Fix date tests withut specified year for current year 2021 (#1774) --- tests/data/Calculation/DateTime/DATEVALUE.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/data/Calculation/DateTime/DATEVALUE.php b/tests/data/Calculation/DateTime/DATEVALUE.php index 0c76eebb..17110c74 100644 --- a/tests/data/Calculation/DateTime/DATEVALUE.php +++ b/tests/data/Calculation/DateTime/DATEVALUE.php @@ -161,12 +161,12 @@ return [ ], // 01/01 of the current year [ - 43831, + 44197, '1 Jan', ], // 31/12 of the current year [ - 44196, + 44561, '31/12', ], // Excel reads as 1st December 1931, not 31st December in current year @@ -176,12 +176,12 @@ return [ ], // 05/07 of the current year [ - 44017, + 44382, '5-JUL', ], // 05/07 of the current year [ - 44017, + 44382, '5 Jul', ], [ From ec51b75fee62aec6d664eda115f08d7849fa0eb9 Mon Sep 17 00:00:00 2001 From: Martins Sipenko Date: Thu, 7 Jan 2021 13:06:26 +0200 Subject: [PATCH 005/187] Mrand of zero to any multiple should return 0 (#1773) --- src/PhpSpreadsheet/Calculation/MathTrig.php | 2 +- tests/data/Calculation/MathTrig/MROUND.php | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 823f6ef2..b8449b55 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -851,7 +851,7 @@ class MathTrig $multiple = Functions::flattenSingleValue($multiple); if ((is_numeric($number)) && (is_numeric($multiple))) { - if ($multiple == 0) { + if ($number == 0 || $multiple == 0) { return 0; } if ((self::SIGN($number)) == (self::SIGN($multiple))) { diff --git a/tests/data/Calculation/MathTrig/MROUND.php b/tests/data/Calculation/MathTrig/MROUND.php index 38017b65..71655485 100644 --- a/tests/data/Calculation/MathTrig/MROUND.php +++ b/tests/data/Calculation/MathTrig/MROUND.php @@ -41,6 +41,11 @@ return [ 31415.92654, 1, ], + [ + 0, + 0, + 5, + ], [ '#NUM!', 5, From 4134ff246ab9477997dbd29f3eb1b739554359e3 Mon Sep 17 00:00:00 2001 From: oleibman Date: Tue, 26 Jan 2021 13:55:06 -0800 Subject: [PATCH 006/187] Problems Using Builtin PHP Functions Directly As Excel Functions (#1799) * Problems Using Builtin PHP Functions Directly As Excel Functions This fixes issue #1789. As originally reported, stricter typing was causing PHP8 to throw an exception when a non-numeric value was passed to the Round function. Previous releases of PHP did not see this problem, however, on further analysis, they were also incorrect in returning 0 as the result in the erroneous situation, when they should have been returning a VALUE error. Yet more analysis showed that other functions would also have problems, and, in addition, might not handle invalid input (e.g. a negative length passed to REPT) or output (e.g. NAN in the case of ACOS(2)) correctly. The following MathTrig functions are affected: ABS, ACOS, ACOSH, ASIN, ASINH, ATAN, ATANH, COS, COSH, DEGREES (rad2deg), EXP, LN (log), LOG10, RADIANS (deg2rad), REPT (str_repeat), SIN, SINH, SQRT, TAN, TANH. One TextData function (REPT) is also affected. This change lets PhpSpreadsheet validate the input for each of these functions before passing control to the builtin, and handle the output afterwards. There were no explicit tests for any of these functions, a fact made easy to ignore by the fact that PhpSpreadsheet delegated the heavy lifting to PHP itself for these cases. A full suite of tests is now added for each of the affected functions. * Scrutinizer Recommendations Only in 3 modules which are part of this PR. * Improved Handling of Tan(PI/2) Return DIV0 error for TAN when COS is very small. * Additional Trig Tests Results which should be infinity, i.e. DIV/0 error. --- .../Calculation/Calculation.php | 42 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 437 +++++++++++++++++- src/PhpSpreadsheet/Calculation/TextData.php | 23 +- .../Functions/MathTrig/AbsTest.php | 36 ++ .../Functions/MathTrig/AcosTest.php | 36 ++ .../Functions/MathTrig/AcoshTest.php | 36 ++ .../Functions/MathTrig/AsinTest.php | 36 ++ .../Functions/MathTrig/AsinhTest.php | 36 ++ .../Functions/MathTrig/AtanTest.php | 36 ++ .../Functions/MathTrig/AtanhTest.php | 36 ++ .../Functions/MathTrig/CosTest.php | 36 ++ .../Functions/MathTrig/CoshTest.php | 36 ++ .../Functions/MathTrig/DegreesTest.php | 36 ++ .../Functions/MathTrig/ExpTest.php | 36 ++ .../Calculation/Functions/MathTrig/LnTest.php | 36 ++ .../Functions/MathTrig/Log10Test.php | 36 ++ .../Functions/MathTrig/RadiansTest.php | 36 ++ .../Functions/MathTrig/RoundTest.php | 40 ++ .../Functions/MathTrig/SinTest.php | 36 ++ .../Functions/MathTrig/SinhTest.php | 36 ++ .../Functions/MathTrig/SqrtTest.php | 36 ++ .../Functions/MathTrig/TanTest.php | 36 ++ .../Functions/MathTrig/TanhTest.php | 36 ++ .../Functions/TextData/ReptTest.php | 40 ++ tests/data/Calculation/MathTrig/ABS.php | 12 + tests/data/Calculation/MathTrig/ACOS.php | 10 + tests/data/Calculation/MathTrig/ACOSH.php | 10 + tests/data/Calculation/MathTrig/ASIN.php | 10 + tests/data/Calculation/MathTrig/ASINH.php | 12 + tests/data/Calculation/MathTrig/ATAN.php | 12 + tests/data/Calculation/MathTrig/ATANH.php | 11 + tests/data/Calculation/MathTrig/COS.php | 12 + tests/data/Calculation/MathTrig/COSH.php | 11 + tests/data/Calculation/MathTrig/COT.php | 8 + tests/data/Calculation/MathTrig/CSC.php | 8 + tests/data/Calculation/MathTrig/DEGREES.php | 7 + tests/data/Calculation/MathTrig/EXP.php | 7 + tests/data/Calculation/MathTrig/LN.php | 11 + tests/data/Calculation/MathTrig/LOG10.php | 12 + tests/data/Calculation/MathTrig/RADIANS.php | 7 + tests/data/Calculation/MathTrig/ROUND.php | 11 + tests/data/Calculation/MathTrig/SEC.php | 8 + tests/data/Calculation/MathTrig/SIN.php | 11 + tests/data/Calculation/MathTrig/SINH.php | 10 + tests/data/Calculation/MathTrig/SQRT.php | 10 + tests/data/Calculation/MathTrig/TAN.php | 13 + tests/data/Calculation/MathTrig/TANH.php | 10 + tests/data/Calculation/TextData/REPT.php | 11 + 48 files changed, 1482 insertions(+), 28 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php create mode 100644 tests/data/Calculation/MathTrig/ABS.php create mode 100644 tests/data/Calculation/MathTrig/ACOS.php create mode 100644 tests/data/Calculation/MathTrig/ACOSH.php create mode 100644 tests/data/Calculation/MathTrig/ASIN.php create mode 100644 tests/data/Calculation/MathTrig/ASINH.php create mode 100644 tests/data/Calculation/MathTrig/ATAN.php create mode 100644 tests/data/Calculation/MathTrig/ATANH.php create mode 100644 tests/data/Calculation/MathTrig/COS.php create mode 100644 tests/data/Calculation/MathTrig/COSH.php create mode 100644 tests/data/Calculation/MathTrig/DEGREES.php create mode 100644 tests/data/Calculation/MathTrig/EXP.php create mode 100644 tests/data/Calculation/MathTrig/LN.php create mode 100644 tests/data/Calculation/MathTrig/LOG10.php create mode 100644 tests/data/Calculation/MathTrig/RADIANS.php create mode 100644 tests/data/Calculation/MathTrig/ROUND.php create mode 100644 tests/data/Calculation/MathTrig/SIN.php create mode 100644 tests/data/Calculation/MathTrig/SINH.php create mode 100644 tests/data/Calculation/MathTrig/SQRT.php create mode 100644 tests/data/Calculation/MathTrig/TAN.php create mode 100644 tests/data/Calculation/MathTrig/TANH.php create mode 100644 tests/data/Calculation/TextData/REPT.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 99260e3b..204b7560 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -228,7 +228,7 @@ class Calculation private static $phpSpreadsheetFunctions = [ 'ABS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'abs', + 'functionCall' => [MathTrig::class, 'builtinABS'], 'argumentCount' => '1', ], 'ACCRINT' => [ @@ -243,12 +243,12 @@ class Calculation ], 'ACOS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'acos', + 'functionCall' => [MathTrig::class, 'builtinACOS'], 'argumentCount' => '1', ], 'ACOSH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'acosh', + 'functionCall' => [MathTrig::class, 'builtinACOSH'], 'argumentCount' => '1', ], 'ACOT' => [ @@ -303,17 +303,17 @@ class Calculation ], 'ASIN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'asin', + 'functionCall' => [MathTrig::class, 'builtinASIN'], 'argumentCount' => '1', ], 'ASINH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'asinh', + 'functionCall' => [MathTrig::class, 'builtinASINH'], 'argumentCount' => '1', ], 'ATAN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'atan', + 'functionCall' => [MathTrig::class, 'builtinATAN'], 'argumentCount' => '1', ], 'ATAN2' => [ @@ -323,7 +323,7 @@ class Calculation ], 'ATANH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'atanh', + 'functionCall' => [MathTrig::class, 'builtinATANH'], 'argumentCount' => '1', ], 'AVEDEV' => [ @@ -604,12 +604,12 @@ class Calculation ], 'COS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'cos', + 'functionCall' => [MathTrig::class, 'builtinCOS'], 'argumentCount' => '1', ], 'COSH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'cosh', + 'functionCall' => [MathTrig::class, 'builtinCOSH'], 'argumentCount' => '1', ], 'COT' => [ @@ -834,7 +834,7 @@ class Calculation ], 'DEGREES' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'rad2deg', + 'functionCall' => [MathTrig::class, 'builtinDEGREES'], 'argumentCount' => '1', ], 'DELTA' => [ @@ -974,7 +974,7 @@ class Calculation ], 'EXP' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'exp', + 'functionCall' => [MathTrig::class, 'builtinEXP'], 'argumentCount' => '1', ], 'EXPONDIST' => [ @@ -1565,7 +1565,7 @@ class Calculation ], 'LN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'log', + 'functionCall' => [MathTrig::class, 'builtinLN'], 'argumentCount' => '1', ], 'LOG' => [ @@ -1575,7 +1575,7 @@ class Calculation ], 'LOG10' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'log10', + 'functionCall' => [MathTrig::class, 'builtinLOG10'], 'argumentCount' => '1', ], 'LOGEST' => [ @@ -2037,7 +2037,7 @@ class Calculation ], 'RADIANS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'deg2rad', + 'functionCall' => [MathTrig::class, 'builtinRADIANS'], 'argumentCount' => '1', ], 'RAND' => [ @@ -2092,7 +2092,7 @@ class Calculation ], 'REPT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => 'str_repeat', + 'functionCall' => [TextData::class, 'builtinREPT'], 'argumentCount' => '2', ], 'RIGHT' => [ @@ -2112,7 +2112,7 @@ class Calculation ], 'ROUND' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'round', + 'functionCall' => [MathTrig::class, 'builtinROUND'], 'argumentCount' => '2', ], 'ROUNDDOWN' => [ @@ -2203,12 +2203,12 @@ class Calculation ], 'SIN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'sin', + 'functionCall' => [MathTrig::class, 'builtinSIN'], 'argumentCount' => '1', ], 'SINH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'sinh', + 'functionCall' => [MathTrig::class, 'builtinSINH'], 'argumentCount' => '1', ], 'SKEW' => [ @@ -2248,7 +2248,7 @@ class Calculation ], 'SQRT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'sqrt', + 'functionCall' => [MathTrig::class, 'builtinSQRT'], 'argumentCount' => '1', ], 'SQRTPI' => [ @@ -2364,12 +2364,12 @@ class Calculation ], 'TAN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'tan', + 'functionCall' => [MathTrig::class, 'builtinTAN'], 'argumentCount' => '1', ], 'TANH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => 'tanh', + 'functionCall' => [MathTrig::class, 'builtinTANH'], 'argumentCount' => '1', ], 'TBILLEQ' => [ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index b8449b55..9ce4a752 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -39,6 +39,13 @@ class MathTrig return ($num - ($num % $n)) / $n; } + private static function strSplit(string $roman): array + { + $rslt = str_split($roman); + + return is_array($rslt) ? $rslt : []; + } + /** * ARABIC. * @@ -66,7 +73,7 @@ class MathTrig } try { - $arabic = self::calculateArabic(str_split($roman)); + $arabic = self::calculateArabic(self::strSplit($roman)); } catch (Exception $e) { return Functions::VALUE(); // Invalid character detected } @@ -1666,7 +1673,7 @@ class MathTrig $result = cos($angle); - return ($result == 0.0) ? Functions::DIV0() : 1 / $result; + return self::verySmallDivisor($result) ? Functions::DIV0() : (1 / $result); } /** @@ -1710,7 +1717,7 @@ class MathTrig $result = sin($angle); - return ($result == 0.0) ? Functions::DIV0() : 1 / $result; + return self::verySmallDivisor($result) ? Functions::DIV0() : (1 / $result); } /** @@ -1752,9 +1759,9 @@ class MathTrig return Functions::VALUE(); } - $result = tan($angle); + $result = sin($angle); - return ($result == 0.0) ? Functions::DIV0() : 1 / $result; + return self::verySmallDivisor($result) ? Functions::DIV0() : (cos($angle) / $result); } /** @@ -1799,6 +1806,18 @@ class MathTrig return (M_PI / 2) - atan($number); } + /** + * Return NAN or value depending on argument. + * + * @param float $result Number + * + * @return float|string + */ + public static function numberOrNan($result) + { + return is_nan($result) ? Functions::NAN() : $result; + } + /** * ACOTH. * @@ -1818,6 +1837,412 @@ class MathTrig $result = log(($number + 1) / ($number - 1)) / 2; - return is_nan($result) ? Functions::NAN() : $result; + return self::numberOrNan($result); + } + + /** + * ROUND. + * + * Returns the result of builtin function round after validating args. + * + * @param mixed $number Should be numeric + * @param mixed $precision Should be int + * + * @return float|string Rounded number + */ + public static function builtinROUND($number, $precision) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number) || !is_numeric($precision)) { + return Functions::VALUE(); + } + + return round($number, $precision); + } + + /** + * ABS. + * + * Returns the result of builtin function abs after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|int|string Rounded number + */ + public static function builtinABS($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return abs($number); + } + + /** + * ACOS. + * + * Returns the result of builtin function acos after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinACOS($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return self::numberOrNan(acos($number)); + } + + /** + * ACOSH. + * + * Returns the result of builtin function acosh after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinACOSH($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return self::numberOrNan(acosh($number)); + } + + /** + * ASIN. + * + * Returns the result of builtin function asin after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinASIN($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return self::numberOrNan(asin($number)); + } + + /** + * ASINH. + * + * Returns the result of builtin function asinh after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinASINH($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return asinh($number); + } + + /** + * ASIN. + * + * Returns the result of builtin function atan after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinATAN($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return self::numberOrNan(atan($number)); + } + + /** + * ATANH. + * + * Returns the result of builtin function atanh after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinATANH($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return atanh($number); + } + + /** + * COS. + * + * Returns the result of builtin function cos after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinCOS($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return cos($number); + } + + /** + * COSH. + * + * Returns the result of builtin function cos after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinCOSH($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return cosh($number); + } + + /** + * DEGREES. + * + * Returns the result of builtin function rad2deg after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinDEGREES($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return rad2deg($number); + } + + /** + * EXP. + * + * Returns the result of builtin function exp after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinEXP($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return exp($number); + } + + /** + * LN. + * + * Returns the result of builtin function log after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinLN($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return log($number); + } + + /** + * LOG10. + * + * Returns the result of builtin function log after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinLOG10($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return log10($number); + } + + /** + * RADIANS. + * + * Returns the result of builtin function deg2rad after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinRADIANS($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return deg2rad($number); + } + + /** + * SIN. + * + * Returns the result of builtin function sin after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinSIN($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return sin($number); + } + + /** + * SINH. + * + * Returns the result of builtin function sinh after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinSINH($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return sinh($number); + } + + /** + * SQRT. + * + * Returns the result of builtin function sqrt after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinSQRT($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return self::numberOrNan(sqrt($number)); + } + + /** + * TAN. + * + * Returns the result of builtin function tan after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinTAN($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return self::verySmallDivisor(cos($number)) ? Functions::DIV0() : tan($number); + } + + /** + * TANH. + * + * Returns the result of builtin function sinh after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function builtinTANH($number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number)) { + return Functions::VALUE(); + } + + return tanh($number); + } + + private static function verySmallDivisor(float $number): bool + { + return abs($number) < 1.0E-12; } } diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index f8974402..16375664 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -162,7 +162,7 @@ class TextData if (!is_numeric($value) || !is_numeric($decimals)) { return Functions::VALUE(); } - $decimals = floor($decimals); + $decimals = (int) $decimals; $mask = '$#,##0'; if ($decimals > 0) { @@ -673,4 +673,25 @@ class TextData return implode($delimiter, $aArgs); } + + /** + * REPT. + * + * Returns the result of builtin function round after validating args. + * + * @param string $str Should be numeric + * @param mixed $number Should be int + * + * @return string + */ + public static function builtinREPT($str, $number) + { + $number = Functions::flattenSingleValue($number); + + if (!is_numeric($number) || $number < 0) { + return Functions::VALUE(); + } + + return str_repeat($str, $number); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php new file mode 100644 index 00000000..49816024 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ABS()'; + } else { + $formula = "=ABS($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerAbs() + { + return require 'tests/data/Calculation/MathTrig/ABS.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php new file mode 100644 index 00000000..825626da --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ACOS()'; + } else { + $formula = "=ACOS($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerAcos() + { + return require 'tests/data/Calculation/MathTrig/ACOS.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php new file mode 100644 index 00000000..bda64d03 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ACOSH()'; + } else { + $formula = "=ACOSH($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerAcosh() + { + return require 'tests/data/Calculation/MathTrig/ACOSH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php new file mode 100644 index 00000000..1edc1c33 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ASIN()'; + } else { + $formula = "=ASIN($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerAsin() + { + return require 'tests/data/Calculation/MathTrig/ASIN.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php new file mode 100644 index 00000000..1621eb79 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ASINH()'; + } else { + $formula = "=ASINH($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerAsinh() + { + return require 'tests/data/Calculation/MathTrig/ASINH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php new file mode 100644 index 00000000..50d76967 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ATAN()'; + } else { + $formula = "=ATAN($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerAtan() + { + return require 'tests/data/Calculation/MathTrig/ATAN.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php new file mode 100644 index 00000000..2863a182 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=ATANH()'; + } else { + $formula = "=ATANH($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerAtanh() + { + return require 'tests/data/Calculation/MathTrig/ATANH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php new file mode 100644 index 00000000..da7a9a15 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=COS()'; + } else { + $formula = "=COS($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerCos() + { + return require 'tests/data/Calculation/MathTrig/COS.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php new file mode 100644 index 00000000..2c452bd5 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=COSH()'; + } else { + $formula = "=COSH($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerCosh() + { + return require 'tests/data/Calculation/MathTrig/COSH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php new file mode 100644 index 00000000..3f92703b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=DEGREES()'; + } else { + $formula = "=DEGREES($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerDegrees() + { + return require 'tests/data/Calculation/MathTrig/DEGREES.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php new file mode 100644 index 00000000..89bc0097 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=EXP()'; + } else { + $formula = "=EXP($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerEXP() + { + return require 'tests/data/Calculation/MathTrig/EXP.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php new file mode 100644 index 00000000..1910ef02 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=LN()'; + } else { + $formula = "=LN($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerLN() + { + return require 'tests/data/Calculation/MathTrig/LN.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php new file mode 100644 index 00000000..e537030c --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=LOG10()'; + } else { + $formula = "=LOG10($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerLN() + { + return require 'tests/data/Calculation/MathTrig/LOG10.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php new file mode 100644 index 00000000..b5849540 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=RADIANS()'; + } else { + $formula = "=RADIANS($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerRADIANS() + { + return require 'tests/data/Calculation/MathTrig/RADIANS.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php new file mode 100644 index 00000000..3cd353a4 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php @@ -0,0 +1,40 @@ +expectException(CalcExp::class); + $formula = '=ROUND()'; + } elseif ($precision === null) { + $this->expectException(CalcExp::class); + $formula = "=ROUND($val)"; + } else { + $formula = "=ROUND($val, $precision)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerRound() + { + return require 'tests/data/Calculation/MathTrig/ROUND.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php new file mode 100644 index 00000000..7a144e0e --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=SIN()'; + } else { + $formula = "=SIN($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerSin() + { + return require 'tests/data/Calculation/MathTrig/SIN.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php new file mode 100644 index 00000000..c24bb192 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=SINH()'; + } else { + $formula = "=SINH($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerCosh() + { + return require 'tests/data/Calculation/MathTrig/SINH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php new file mode 100644 index 00000000..972035e7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=SQRT()'; + } else { + $formula = "=SQRT($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerSqrt() + { + return require 'tests/data/Calculation/MathTrig/SQRT.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php new file mode 100644 index 00000000..13093f6a --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=TAN()'; + } else { + $formula = "=TAN($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerTan() + { + return require 'tests/data/Calculation/MathTrig/TAN.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php new file mode 100644 index 00000000..69f28e8a --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php @@ -0,0 +1,36 @@ +expectException(CalcExp::class); + $formula = '=TANH()'; + } else { + $formula = "=TANH($val)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + } + + public function providerTanh() + { + return require 'tests/data/Calculation/MathTrig/TANH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php new file mode 100644 index 00000000..cb4f1586 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php @@ -0,0 +1,40 @@ +expectException(CalcExp::class); + $formula = '=REPT()'; + } elseif ($rpt === null) { + $this->expectException(CalcExp::class); + $formula = "=REPT($val)"; + } else { + $formula = "=REPT($val, $rpt)"; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue($formula); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function providerREPT() + { + return require 'tests/data/Calculation/TextData/REPT.php'; + } +} diff --git a/tests/data/Calculation/MathTrig/ABS.php b/tests/data/Calculation/MathTrig/ABS.php new file mode 100644 index 00000000..2fc9631b --- /dev/null +++ b/tests/data/Calculation/MathTrig/ABS.php @@ -0,0 +1,12 @@ + Date: Thu, 28 Jan 2021 01:52:54 -0800 Subject: [PATCH 007/187] Delete Temporary Files In XssVulnerabilityTest (#1800) * Delete Temporary Files In XssVulnerabilityTest They need not exist after the test. Some of them are placed in current directory, which means Git thinks they are needed. --- .../Writer/Html/XssVulnerabilityTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php b/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php index 48aced02..de0ac54d 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php @@ -43,6 +43,7 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional $writer->save($filename); $verify = file_get_contents($filename); + unlink($filename); // Ensure that executable js has been stripped from the comments self::assertStringContainsString($adjustedTextString, $verify); } @@ -58,8 +59,6 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional ]; } - private static $counter = 0; - /** * @dataProvider providerXssRichText * @@ -84,8 +83,7 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional $writer->save($filename); $verify = file_get_contents($filename); - $counter = self::$counter++; - file_put_contents("verify{$counter}.html", $verify); + unlink($filename); // Ensure that executable js has been stripped from the comments self::assertStringNotContainsString($xssTextString, $verify); } From ff784b5f2c2dabe93a6a9612c6b099c99f4e6374 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Thu, 28 Jan 2021 12:22:33 +0100 Subject: [PATCH 008/187] Update Changelog for switch from built-in PHP functions to Excel class methods (to handle typechecking for stricter PHP8 typing) --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4741afe..93582fe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,14 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Changed -- Nothing. +- Formula functions that previously called PHP functions directly are now processed through the Excel Functions classes; resolving issues with PHP8 stricter typing. [#1789](https://github.com/PHPOffice/PhpSpreadsheet/issues/1789) + + The following MathTrig functions are affected: + `ABS()`, `ACOS()`, `ACOSH()`, `ASIN()`, `ASINH()`, `ATAN()`, `ATANH()`, + `COS()`, `COSH()`, `DEGREES()` (rad2deg), `EXP()`, `LN()` (log), `LOG10()`, + `RADIANS()` (deg2rad), `SIN()`, `SINH()`, `SQRT()`, `TAN()`, `TANH()`. + + One TextData function is also affected: `REPT()` (str_repeat). ### Deprecated From a66233b72f4d4859b3e83dcb6d74a39ba8aa1818 Mon Sep 17 00:00:00 2001 From: oleibman Date: Thu, 28 Jan 2021 03:42:41 -0800 Subject: [PATCH 009/187] Fix For #1772 Null Exception on ODS Read (#1776) Fix for #1772. Header and Footer Properties may be omitted in Page Setting Style Set. Code changed to allow for this possibility, and tests added. --- .../Reader/Ods/PageSettings.php | 4 +- .../Reader/Ods/PageSetupBug1772Test.php | 98 ++++++++++++++++++ tests/data/Reader/Ods/bug1772.ods | Bin 0 -> 11652 bytes 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php create mode 100644 tests/data/Reader/Ods/bug1772.ods diff --git a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php index 77341aab..8d24fd0c 100644 --- a/src/PhpSpreadsheet/Reader/Ods/PageSettings.php +++ b/src/PhpSpreadsheet/Reader/Ods/PageSettings.php @@ -54,10 +54,10 @@ class PageSettings $marginBottom = $pageLayoutProperties->getAttributeNS($this->stylesFo, 'margin-bottom'); $header = $styleSet->getElementsByTagNameNS($this->stylesNs, 'header-style')[0]; $headerProperties = $header->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0]; - $marginHeader = $headerProperties->getAttributeNS($this->stylesFo, 'min-height'); + $marginHeader = isset($headerProperties) ? $headerProperties->getAttributeNS($this->stylesFo, 'min-height') : null; $footer = $styleSet->getElementsByTagNameNS($this->stylesNs, 'footer-style')[0]; $footerProperties = $footer->getElementsByTagNameNS($this->stylesNs, 'header-footer-properties')[0]; - $marginFooter = $footerProperties->getAttributeNS($this->stylesFo, 'min-height'); + $marginFooter = isset($footerProperties) ? $footerProperties->getAttributeNS($this->stylesFo, 'min-height') : null; $this->pageLayoutStyles[$styleName] = (object) [ 'orientation' => $styleOrientation ?: PageSetup::ORIENTATION_DEFAULT, diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php b/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php new file mode 100644 index 00000000..883664fc --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php @@ -0,0 +1,98 @@ +spreadsheet = $reader->load($filename); + } + + public function testPageSetup(): void + { + $assertions = $this->pageSetupAssertions(); + + foreach ($this->spreadsheet->getAllSheets() as $worksheet) { + if (!array_key_exists($worksheet->getTitle(), $assertions)) { + continue; + } + + $sheetAssertions = $assertions[$worksheet->getTitle()]; + foreach ($sheetAssertions as $test => $expectedResult) { + $testMethodName = 'get' . ucfirst($test); + $actualResult = $worksheet->getPageSetup()->$testMethodName(); + self::assertSame( + $expectedResult, + $actualResult, + "Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test}" + ); + } + } + } + + public function testPageMargins(): void + { + $assertions = $this->pageMarginAssertions(); + + foreach ($this->spreadsheet->getAllSheets() as $worksheet) { + if (!array_key_exists($worksheet->getTitle(), $assertions)) { + continue; + } + + $sheetAssertions = $assertions[$worksheet->getTitle()]; + foreach ($sheetAssertions as $test => $expectedResult) { + $testMethodName = 'get' . ucfirst($test); + $actualResult = $worksheet->getPageMargins()->$testMethodName(); + self::assertEqualsWithDelta( + $expectedResult, + $actualResult, + self::MARGIN_PRECISION, + "Failed assertion for Worksheet '{$worksheet->getTitle()}' {$test} margin" + ); + } + } + } + + private function pageSetupAssertions(): array + { + return [ + 'Employee update template' => [ + 'orientation' => PageSetup::ORIENTATION_DEFAULT, + 'scale' => 100, + 'horizontalCentered' => false, + 'verticalCentered' => false, + 'pageOrder' => PageSetup::PAGEORDER_DOWN_THEN_OVER, + ], + ]; + } + + private function pageMarginAssertions(): array + { + return [ + 'Employee update template' => [ + // Here the values are in cm + 'top' => 0.0, + 'header' => 0.2953, + 'left' => 0.0, + 'right' => 0.0, + 'bottom' => 0.0, + 'footer' => 0.2953, + ], + ]; + } +} diff --git a/tests/data/Reader/Ods/bug1772.ods b/tests/data/Reader/Ods/bug1772.ods new file mode 100644 index 0000000000000000000000000000000000000000..a4a3c2ac582f2baa8f9d6ee6bb9adeba3d783af1 GIT binary patch literal 11652 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 z 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 literal 0 HcmV?d00001 From a0ef2b8ce1e2728e04c727a80f9fc390e074682e Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Thu, 28 Jan 2021 12:55:17 +0100 Subject: [PATCH 010/187] Additional method call/return typing --- src/PhpSpreadsheet/Calculation/Calculation.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 204b7560..b5fc1992 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -2695,12 +2695,12 @@ class Calculation /** * Get an instance of this class. * - * @param Spreadsheet $spreadsheet Injected spreadsheet for working with a PhpSpreadsheet Spreadsheet object, + * @param ?Spreadsheet $spreadsheet Injected spreadsheet for working with a PhpSpreadsheet Spreadsheet object, * or NULL to create a standalone claculation engine * * @return Calculation */ - public static function getInstance(?Spreadsheet $spreadsheet = null) + public static function getInstance(?Spreadsheet $spreadsheet = null): Calculation { if ($spreadsheet !== null) { $instance = $spreadsheet->getCalculationEngine(); @@ -2738,6 +2738,8 @@ class Calculation /** * __clone implementation. Cloning should not be allowed in a Singleton! + * + * @throws Exception */ final public function __clone() { @@ -2749,7 +2751,7 @@ class Calculation * * @return string locale-specific translation of TRUE */ - public static function getTRUE() + public static function getTRUE(): string { return self::$localeBoolean['TRUE']; } @@ -2759,7 +2761,7 @@ class Calculation * * @return string locale-specific translation of FALSE */ - public static function getFALSE() + public static function getFALSE(): string { return self::$localeBoolean['FALSE']; } From e7bbc515da202615aa012cbb0185cc9545a0b717 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Thu, 28 Jan 2021 13:09:50 +0100 Subject: [PATCH 011/187] Update Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93582fe1..cf20bf55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Nothing. +- Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) ## 1.16.0 - 2020-12-31 From e1ed52ecb60cd48b1579ef5cbe26bea1588465aa Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Thu, 28 Jan 2021 15:18:41 +0100 Subject: [PATCH 012/187] PHPCS Resolutions --- src/PhpSpreadsheet/Calculation/Calculation.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index b5fc1992..72aa9a51 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -2697,10 +2697,8 @@ class Calculation * * @param ?Spreadsheet $spreadsheet Injected spreadsheet for working with a PhpSpreadsheet Spreadsheet object, * or NULL to create a standalone claculation engine - * - * @return Calculation */ - public static function getInstance(?Spreadsheet $spreadsheet = null): Calculation + public static function getInstance(?Spreadsheet $spreadsheet = null): self { if ($spreadsheet !== null) { $instance = $spreadsheet->getCalculationEngine(); @@ -2738,8 +2736,6 @@ class Calculation /** * __clone implementation. Cloning should not be allowed in a Singleton! - * - * @throws Exception */ final public function __clone() { From 87c8e95ae9db77e2123f8fa36cd811d5f8563762 Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Thu, 28 Jan 2021 21:46:36 +0100 Subject: [PATCH 013/187] Fix Xlsx reader overriding manually set number format with builtin number format (#1805) --- src/PhpSpreadsheet/Reader/Xlsx.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 124cc3b2..4222b954 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -488,7 +488,7 @@ class Xlsx extends BaseReader } if (!$this->readDataOnly && $xmlStyles) { foreach ($xmlStyles->cellXfs->xf as $xf) { - $numFmt = NumberFormat::FORMAT_GENERAL; + $numFmt = null; if ($xf['numFmtId']) { if (isset($numFmts)) { @@ -503,6 +503,7 @@ class Xlsx extends BaseReader // But there's a lot of naughty homebrew xlsx writers that do use "reserved" id values that aren't actually used // So we make allowance for them rather than lose formatting masks if ( + $numFmt === null && (int) $xf['numFmtId'] < 164 && NumberFormat::builtInFormatCode((int) $xf['numFmtId']) !== '' ) { @@ -515,7 +516,7 @@ class Xlsx extends BaseReader } $style = (object) [ - 'numFmt' => $numFmt, + 'numFmt' => $numFmt === null ? NumberFormat::FORMAT_GENERAL : $numFmt, 'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])], 'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])], 'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])], From f1b63b7984ec7b6018923b886b4f6dde0714a956 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Thu, 28 Jan 2021 21:51:40 +0100 Subject: [PATCH 014/187] Update Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf20bf55..8366cb3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) +- Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) ## 1.16.0 - 2020-12-31 From 65837daa983762ba931558929e9ba0b9949c597f Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 29 Jan 2021 15:43:49 +0100 Subject: [PATCH 015/187] Named formula fix for empty formula value --- composer.json | 2 +- src/PhpSpreadsheet/NamedFormula.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index c6f8e30e..0fffd510 100644 --- a/composer.json +++ b/composer.json @@ -63,7 +63,7 @@ }, "require-dev": { "dompdf/dompdf": "^0.8.5", - "friendsofphp/php-cs-fixer": "^2.16", + "friendsofphp/php-cs-fixer": "^2.16||^2.18", "jpgraph/jpgraph": "^4.0", "mpdf/mpdf": "^8.0", "phpcompatibility/php-compatibility": "^9.3", diff --git a/src/PhpSpreadsheet/NamedFormula.php b/src/PhpSpreadsheet/NamedFormula.php index eeddbbcb..500151f0 100644 --- a/src/PhpSpreadsheet/NamedFormula.php +++ b/src/PhpSpreadsheet/NamedFormula.php @@ -17,7 +17,7 @@ class NamedFormula extends DefinedName ?Worksheet $scope = null ) { // Validate data - if (empty($formula)) { + if (!isset($formula)) { throw new Exception('You must specify a Formula value for a Named Formula'); } parent::__construct($name, $worksheet, $formula, $localOnly, $scope); From 97aa78fc9a6f6f497ef2f35375ce4379c3a9cf9c Mon Sep 17 00:00:00 2001 From: Jasper Zonneveld Date: Fri, 29 Jan 2021 15:57:56 +0100 Subject: [PATCH 016/187] Do not swallow previous exception (#1778) The previous exception will be included when loading the content as DOM Document fails. This makes debugging the reason behind the failure much easier. --- src/PhpSpreadsheet/Reader/Html.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index 73f4591e..e1139015 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -650,7 +650,7 @@ class Html extends BaseReader $loaded = false; } if ($loaded === false) { - throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document'); + throw new Exception('Failed to load ' . $pFilename . ' as a DOM Document', 0, $e ?? null); } return $this->loadDocument($dom, $spreadsheet); @@ -672,7 +672,7 @@ class Html extends BaseReader $loaded = false; } if ($loaded === false) { - throw new Exception('Failed to load content as a DOM Document'); + throw new Exception('Failed to load content as a DOM Document', 0, $e ?? null); } return $this->loadDocument($dom, $spreadsheet ?? new Spreadsheet()); From 8d2d78334f2c34a0774de890f00ec0db4644ebbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=82=E3=82=8A=E3=82=82=E3=81=A8=20=E3=81=9F=E3=81=8B?= =?UTF-8?q?=E3=81=B2=E3=82=8D?= Date: Sat, 30 Jan 2021 00:57:40 +0900 Subject: [PATCH 017/187] Support DataBar of conditional formatting rule (#1754) Implemented the databar of Conditional Type for XLSX Files. - DataBar can be read, written, and added for basic use. - Supports reading, writing and adding using "extLst". About "extLst" - https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627 The following setting items on the Excel setting screen can be read, written, and added. - (minimum, maximum)type: Automatic, LowestValue, Number, Percent, Formula, Percentile - Direction: context, leftToRight, rightToLeft (show data bar only) - Fills Solid, Gradient - FillColor: PositiveValues, NegativeValues - Borders: Solid, None - BorderColor: PositiveValues, NegativeValues - Axis position: Automatic, Midpoint, None - Axis color --- CHANGELOG.md | 2 +- .../10-databar-of-conditional-formatting.png | Bin 0 -> 143616 bytes docs/topics/recipes.md | 38 ++ .../Reader/Xlsx/ConditionalStyles.php | 79 ++++- src/PhpSpreadsheet/Style/Conditional.php | 29 ++ .../ConditionalDataBar.php | 102 ++++++ .../ConditionalDataBarExtension.php | 290 ++++++++++++++++ .../ConditionalFormatValueObject.php | 80 +++++ .../ConditionalFormattingRuleExtension.php | 197 +++++++++++ src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 141 +++++++- .../ConditionalFormattingDataBarXlsxTest.php | 325 ++++++++++++++++++ .../conditionalFormattingDataBarTest.xlsx | Bin 0 -> 10443 bytes 12 files changed, 1270 insertions(+), 13 deletions(-) create mode 100644 docs/topics/images/10-databar-of-conditional-formatting.png create mode 100644 src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php create mode 100644 src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php create mode 100644 src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php create mode 100644 src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php create mode 100644 tests/data/Reader/XLSX/conditionalFormattingDataBarTest.xlsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 8366cb3b..cefe1590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Nothing. +- Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754) ### Changed diff --git a/docs/topics/images/10-databar-of-conditional-formatting.png b/docs/topics/images/10-databar-of-conditional-formatting.png new file mode 100644 index 0000000000000000000000000000000000000000..10c88f9f779317f7eaac4cfe9918b67969dc190e GIT binary patch literal 143616 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

pR!2!?M&CxOQ+SgakSwcQ1RER2(8!s6kL6!k~Z) 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 ); ``` +### DataBar of Conditional formatting +The basics are the same as conditional formatting. +Additional DataBar object to conditional formatting. + +For example, the following code will result in the conditional formatting shown in the image. +```php +$conditional = new Conditional(); +$conditional->setConditionType(Conditional::CONDITION_DATABAR); +$conditional->setDataBar(new ConditionalDataBar()); +$conditional->getDataBar() + ->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject('num', '2')) + ->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject('max')) + ->setColor('FFFF555A'); +$ext = $conditional + ->getDataBar() + ->setConditionalFormattingRuleExt(new ConditionalFormattingRuleExtension()) + ->getConditionalFormattingRuleExt(); + +$ext->setCfRule('dataBar'); +$ext->setSqref('A1:A5'); // target CellCoordinates +$ext->setDataBarExt(new ConditionalDataBarExtension()); +$ext->getDataBarExt() + ->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject('num', '2')) + ->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject('autoMax')) + ->setMinLength(0) + ->setMaxLength(100) + ->setBorder(true) + ->setDirection('rightToLeft') + ->setNegativeBarBorderColorSameAsPositive(false) + ->setBorderColor('FFFF555A') + ->setNegativeFillColor('FFFF0000') + ->setNegativeBorderColor('FFFF0000') + ->setAxisColor('FF000000'); + +``` + +![10-databar-of-conditional-formatting.png](./images/10-databar-of-conditional-formatting.png) + ## Add a comment to a cell To add a comment to a cell, use the following code. The example below diff --git a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php index 4aa48e17..7f96956f 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php @@ -2,7 +2,11 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx; +use PhpOffice\PhpSpreadsheet\Style\Color; use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormatValueObject; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use SimpleXMLElement; @@ -25,7 +29,8 @@ class ConditionalStyles { $this->setConditionalStyles( $this->worksheet, - $this->readConditionalStyles($this->worksheetXml) + $this->readConditionalStyles($this->worksheetXml), + $this->worksheetXml->extLst ); } @@ -36,14 +41,16 @@ class ConditionalStyles foreach ($conditional->cfRule as $cfRule) { if ( ((string) $cfRule['type'] == Conditional::CONDITION_NONE - || (string) $cfRule['type'] == Conditional::CONDITION_CELLIS - || (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT - || (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS - || (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS - || (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION) + || (string) $cfRule['type'] == Conditional::CONDITION_CELLIS + || (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSTEXT + || (string) $cfRule['type'] == Conditional::CONDITION_CONTAINSBLANKS + || (string) $cfRule['type'] == Conditional::CONDITION_NOTCONTAINSBLANKS + || (string) $cfRule['type'] == Conditional::CONDITION_EXPRESSION) && isset($this->dxfs[(int) ($cfRule['dxfId'])]) ) { $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule; + } elseif ((string) $cfRule['type'] == Conditional::CONDITION_DATABAR) { + $conditionals[(string) $conditional['sqref']][(int) ($cfRule['priority'])] = $cfRule; } } } @@ -51,11 +58,11 @@ class ConditionalStyles return $conditionals; } - private function setConditionalStyles(Worksheet $worksheet, array $conditionals): void + private function setConditionalStyles(Worksheet $worksheet, array $conditionals, $xmlExtLst): void { foreach ($conditionals as $ref => $cfRules) { ksort($cfRules); - $conditionalStyles = $this->readStyleRules($cfRules); + $conditionalStyles = $this->readStyleRules($cfRules, $xmlExtLst); // Extract all cell references in $ref $cellBlocks = explode(' ', str_replace('$', '', strtoupper($ref))); @@ -65,8 +72,9 @@ class ConditionalStyles } } - private function readStyleRules($cfRules) + private function readStyleRules($cfRules, $extLst) { + $conditionalFormattingRuleExtensions = ConditionalFormattingRuleExtension::parseExtLstXml($extLst); $conditionalStyles = []; foreach ($cfRules as $cfRule) { $objConditional = new Conditional(); @@ -88,10 +96,61 @@ class ConditionalStyles } else { $objConditional->addCondition((string) $cfRule->formula); } - $objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]); + + if (isset($cfRule->dataBar)) { + $objConditional->setDataBar($this->readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions)); + } else { + $objConditional->setStyle(clone $this->dxfs[(int) ($cfRule['dxfId'])]); + } + $conditionalStyles[] = $objConditional; } return $conditionalStyles; } + + private function readDataBarOfConditionalRule($cfRule, $conditionalFormattingRuleExtensions): ConditionalDataBar + { + $dataBar = new ConditionalDataBar(); + //dataBar attribute + if (isset($cfRule->dataBar['showValue'])) { + $dataBar->setShowValue((bool) $cfRule->dataBar['showValue']); + } + + //dataBar children + //conditionalFormatValueObjects + $cfvoXml = $cfRule->dataBar->cfvo; + $cfvoIndex = 0; + foreach ((count($cfvoXml) > 1 ? $cfvoXml : [$cfvoXml]) as $cfvo) { + if ($cfvoIndex === 0) { + $dataBar->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val'])); + } + if ($cfvoIndex === 1) { + $dataBar->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo['type'], (string) $cfvo['val'])); + } + ++$cfvoIndex; + } + + //color + if (isset($cfRule->dataBar->color)) { + $dataBar->setColor((string) $cfRule->dataBar->color['rgb']); + } + //extLst + $this->readDataBarExtLstOfConditionalRule($dataBar, $cfRule, $conditionalFormattingRuleExtensions); + + return $dataBar; + } + + private function readDataBarExtLstOfConditionalRule(ConditionalDataBar $dataBar, $cfRule, $conditionalFormattingRuleExtensions): void + { + if (isset($cfRule->extLst)) { + $ns = $cfRule->extLst->getNamespaces(true); + foreach ((count($cfRule->extLst) > 0 ? $cfRule->extLst->ext : [$cfRule->extLst->ext]) as $ext) { + $extId = (string) $ext->children($ns['x14'])->id; + if (isset($conditionalFormattingRuleExtensions[$extId]) && (string) $ext['uri'] === '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}') { + $dataBar->setConditionalFormattingRuleExt($conditionalFormattingRuleExtensions[$extId]); + } + } + } + } } diff --git a/src/PhpSpreadsheet/Style/Conditional.php b/src/PhpSpreadsheet/Style/Conditional.php index e4fe0acc..b008c9f2 100644 --- a/src/PhpSpreadsheet/Style/Conditional.php +++ b/src/PhpSpreadsheet/Style/Conditional.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Style; use PhpOffice\PhpSpreadsheet\IComparable; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; class Conditional implements IComparable { @@ -13,6 +14,7 @@ class Conditional implements IComparable const CONDITION_EXPRESSION = 'expression'; const CONDITION_CONTAINSBLANKS = 'containsBlanks'; const CONDITION_NOTCONTAINSBLANKS = 'notContainsBlanks'; + const CONDITION_DATABAR = 'dataBar'; // Operator types const OPERATOR_NONE = ''; @@ -64,6 +66,11 @@ class Conditional implements IComparable */ private $condition = []; + /** + * @var ConditionalDataBar + */ + private $dataBar; + /** * Style. * @@ -241,6 +248,28 @@ class Conditional implements IComparable return $this; } + /** + * get DataBar. + * + * @return ConditionalDataBar | null + */ + public function getDataBar() + { + return $this->dataBar; + } + + /** + * set DataBar. + * + * @return $this + */ + public function setDataBar(ConditionalDataBar $dataBar) + { + $this->dataBar = $dataBar; + + return $this; + } + /** * Get hash code. * diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php new file mode 100644 index 00000000..54513670 --- /dev/null +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php @@ -0,0 +1,102 @@ + attribute */ + + /** @var null|bool */ + private $showValue; + + /** children */ + + /** @var ConditionalFormatValueObject */ + private $minimumConditionalFormatValueObject; + + /** @var ConditionalFormatValueObject */ + private $maximumConditionalFormatValueObject; + + /** @var string */ + private $color; + + /** */ + + /** @var ConditionalFormattingRuleExtension */ + private $conditionalFormattingRuleExt; + + /** + * @return null|bool + */ + public function getShowValue() + { + return $this->showValue; + } + + /** + * @param bool $showValue + */ + public function setShowValue($showValue) + { + $this->showValue = $showValue; + + return $this; + } + + /** + * @return ConditionalFormatValueObject + */ + public function getMinimumConditionalFormatValueObject() + { + return $this->minimumConditionalFormatValueObject; + } + + public function setMinimumConditionalFormatValueObject(ConditionalFormatValueObject $minimumConditionalFormatValueObject) + { + $this->minimumConditionalFormatValueObject = $minimumConditionalFormatValueObject; + + return $this; + } + + /** + * @return ConditionalFormatValueObject + */ + public function getMaximumConditionalFormatValueObject() + { + return $this->maximumConditionalFormatValueObject; + } + + public function setMaximumConditionalFormatValueObject(ConditionalFormatValueObject $maximumConditionalFormatValueObject) + { + $this->maximumConditionalFormatValueObject = $maximumConditionalFormatValueObject; + + return $this; + } + + public function getColor(): string + { + return $this->color; + } + + public function setColor(string $color): self + { + $this->color = $color; + + return $this; + } + + /** + * @return ConditionalFormattingRuleExtension + */ + public function getConditionalFormattingRuleExt() + { + return $this->conditionalFormattingRuleExt; + } + + public function setConditionalFormattingRuleExt(ConditionalFormattingRuleExtension $conditionalFormattingRuleExt) + { + $this->conditionalFormattingRuleExt = $conditionalFormattingRuleExt; + + return $this; + } +} diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php new file mode 100644 index 00000000..c709cf3e --- /dev/null +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php @@ -0,0 +1,290 @@ + attributes */ + + /** @var int */ + private $minLength; + + /** @var int */ + private $maxLength; + + /** @var null|bool */ + private $border; + + /** @var null|bool */ + private $gradient; + + /** @var string */ + private $direction; + + /** @var null|bool */ + private $negativeBarBorderColorSameAsPositive; + + /** @var string */ + private $axisPosition; + + // children + + /** @var ConditionalFormatValueObject */ + private $maximumConditionalFormatValueObject; + + /** @var ConditionalFormatValueObject */ + private $minimumConditionalFormatValueObject; + + /** @var string */ + private $borderColor; + + /** @var string */ + private $negativeFillColor; + + /** @var string */ + private $negativeBorderColor; + + /** @var array */ + private $axisColor = [ + 'rgb' => null, + 'theme' => null, + 'tint' => null, + ]; + + public function getXmlAttributes() + { + $ret = []; + foreach (['minLength', 'maxLength', 'direction', 'axisPosition'] as $attrKey) { + if (null !== $this->{$attrKey}) { + $ret[$attrKey] = $this->{$attrKey}; + } + } + foreach (['border', 'gradient', 'negativeBarBorderColorSameAsPositive'] as $attrKey) { + if (null !== $this->{$attrKey}) { + $ret[$attrKey] = $this->{$attrKey} ? '1' : '0'; + } + } + + return $ret; + } + + public function getXmlElements() + { + $ret = []; + $elms = ['borderColor', 'negativeFillColor', 'negativeBorderColor']; + foreach ($elms as $elmKey) { + if (null !== $this->{$elmKey}) { + $ret[$elmKey] = ['rgb' => $this->{$elmKey}]; + } + } + foreach (array_filter($this->axisColor) as $attrKey => $axisColorAttr) { + if (!isset($ret['axisColor'])) { + $ret['axisColor'] = []; + } + $ret['axisColor'][$attrKey] = $axisColorAttr; + } + + return $ret; + } + + /** + * @return int + */ + public function getMinLength() + { + return $this->minLength; + } + + public function setMinLength(int $minLength): self + { + $this->minLength = $minLength; + + return $this; + } + + /** + * @return int + */ + public function getMaxLength() + { + return $this->maxLength; + } + + public function setMaxLength(int $maxLength): self + { + $this->maxLength = $maxLength; + + return $this; + } + + /** + * @return null|bool + */ + public function getBorder() + { + return $this->border; + } + + public function setBorder(bool $border): self + { + $this->border = $border; + + return $this; + } + + /** + * @return null|bool + */ + public function getGradient() + { + return $this->gradient; + } + + public function setGradient(bool $gradient): self + { + $this->gradient = $gradient; + + return $this; + } + + /** + * @return string + */ + public function getDirection() + { + return $this->direction; + } + + public function setDirection(string $direction): self + { + $this->direction = $direction; + + return $this; + } + + /** + * @return null|bool + */ + public function getNegativeBarBorderColorSameAsPositive() + { + return $this->negativeBarBorderColorSameAsPositive; + } + + public function setNegativeBarBorderColorSameAsPositive(bool $negativeBarBorderColorSameAsPositive): self + { + $this->negativeBarBorderColorSameAsPositive = $negativeBarBorderColorSameAsPositive; + + return $this; + } + + /** + * @return string + */ + public function getAxisPosition() + { + return $this->axisPosition; + } + + public function setAxisPosition(string $axisPosition): self + { + $this->axisPosition = $axisPosition; + + return $this; + } + + /** + * @return ConditionalFormatValueObject + */ + public function getMaximumConditionalFormatValueObject() + { + return $this->maximumConditionalFormatValueObject; + } + + public function setMaximumConditionalFormatValueObject(ConditionalFormatValueObject $maximumConditionalFormatValueObject) + { + $this->maximumConditionalFormatValueObject = $maximumConditionalFormatValueObject; + + return $this; + } + + /** + * @return ConditionalFormatValueObject + */ + public function getMinimumConditionalFormatValueObject() + { + return $this->minimumConditionalFormatValueObject; + } + + public function setMinimumConditionalFormatValueObject(ConditionalFormatValueObject $minimumConditionalFormatValueObject) + { + $this->minimumConditionalFormatValueObject = $minimumConditionalFormatValueObject; + + return $this; + } + + /** + * @return string + */ + public function getBorderColor() + { + return $this->borderColor; + } + + public function setBorderColor(string $borderColor): self + { + $this->borderColor = $borderColor; + + return $this; + } + + /** + * @return string + */ + public function getNegativeFillColor() + { + return $this->negativeFillColor; + } + + public function setNegativeFillColor(string $negativeFillColor): self + { + $this->negativeFillColor = $negativeFillColor; + + return $this; + } + + /** + * @return string + */ + public function getNegativeBorderColor() + { + return $this->negativeBorderColor; + } + + public function setNegativeBorderColor(string $negativeBorderColor): self + { + $this->negativeBorderColor = $negativeBorderColor; + + return $this; + } + + public function getAxisColor(): array + { + return $this->axisColor; + } + + /** + * @param mixed $rgb + * @param null|mixed $theme + * @param null|mixed $tint + */ + public function setAxisColor($rgb, $theme = null, $tint = null): self + { + $this->axisColor = [ + 'rgb' => $rgb, + 'theme' => $theme, + 'tint' => $tint, + ]; + + return $this; + } +} diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php new file mode 100644 index 00000000..c6370b86 --- /dev/null +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php @@ -0,0 +1,80 @@ +type = $type; + $this->value = $value; + $this->cellFormula = $cellFormula; + } + + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * @param mixed $type + */ + public function setType($type) + { + $this->type = $type; + + return $this; + } + + /** + * @return mixed + */ + public function getValue() + { + return $this->value; + } + + /** + * @param mixed $value + */ + public function setValue($value) + { + $this->value = $value; + + return $this; + } + + /** + * @return mixed + */ + public function getCellFormula() + { + return $this->cellFormula; + } + + /** + * @param mixed $cellFormula + */ + public function setCellFormula($cellFormula) + { + $this->cellFormula = $cellFormula; + + return $this; + } +} diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php new file mode 100644 index 00000000..943c734b --- /dev/null +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php @@ -0,0 +1,197 @@ + attributes */ + private $id; + + /** @var string Conditional Formatting Rule */ + private $cfRule; + + /** children */ + + /** @var ConditionalDataBarExtension */ + private $dataBar; + + /** @var string Sequence of References */ + private $sqref; + + /** + * ConditionalFormattingRuleExtension constructor. + * + * @param $id + */ + public function __construct($id = null, string $cfRule = self::CONDITION_EXTENSION_DATABAR) + { + if (null === $id) { + $this->id = '{' . $this->generateUuid() . '}'; + } else { + $this->id = $id; + } + $this->cfRule = $cfRule; + } + + private function generateUuid() + { + $chars = str_split('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'); + + foreach ($chars as $i => $char) { + if ($char === 'x') { + $chars[$i] = dechex(random_int(0, 15)); + } elseif ($char === 'y') { + $chars[$i] = dechex(random_int(8, 11)); + } + } + + return implode('', $chars); + } + + public static function parseExtLstXml($extLstXml) + { + $conditionalFormattingRuleExtensions = []; + $conditionalFormattingRuleExtensionXml = null; + if ($extLstXml instanceof SimpleXMLElement) { + foreach ((count($extLstXml) > 0 ? $extLstXml : [$extLstXml]) as $extLst) { + //this uri is conditionalFormattings + //https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627 + if (isset($extLst->ext['uri']) && (string) $extLst->ext['uri'] === '{78C0D931-6437-407d-A8EE-F0AAD7539E65}') { + $conditionalFormattingRuleExtensionXml = $extLst->ext; + } + } + if ($conditionalFormattingRuleExtensionXml) { + $ns = $conditionalFormattingRuleExtensionXml->getNamespaces(true); + $extFormattingsXml = $conditionalFormattingRuleExtensionXml->children($ns['x14']); + + foreach ($extFormattingsXml->children($ns['x14']) as $extFormattingXml) { + $extCfRuleXml = $extFormattingXml->cfRule; + $extFormattingRuleObj = new self((string) $extCfRuleXml->attributes()->id); + $extFormattingRuleObj->setSqref((string) $extFormattingXml->children($ns['xm'])->sqref); + $conditionalFormattingRuleExtensions[$extFormattingRuleObj->getId()] = $extFormattingRuleObj; + + $extDataBarObj = new ConditionalDataBarExtension(); + $extFormattingRuleObj->setDataBarExt($extDataBarObj); + + $dataBarXml = $extCfRuleXml->dataBar; + self::parseExtDataBarAttributesFromXml($extDataBarObj, $dataBarXml); + self::parseExtDataBarElementChildrenFromXml($extDataBarObj, $dataBarXml, $ns); + } + } + } + + return $conditionalFormattingRuleExtensions; + } + + private static function parseExtDataBarAttributesFromXml(ConditionalDataBarExtension $extDataBarObj, SimpleXMLElement $dataBarXml): void + { + $dataBarAttribute = $dataBarXml->attributes(); + if ($dataBarAttribute->minLength) { + $extDataBarObj->setMinLength((int) $dataBarAttribute->minLength); + } + if ($dataBarAttribute->maxLength) { + $extDataBarObj->setMaxLength((int) $dataBarAttribute->maxLength); + } + if ($dataBarAttribute->border) { + $extDataBarObj->setBorder((bool) (string) $dataBarAttribute->border); + } + if ($dataBarAttribute->gradient) { + $extDataBarObj->setGradient((bool) (string) $dataBarAttribute->gradient); + } + if ($dataBarAttribute->direction) { + $extDataBarObj->setDirection((string) $dataBarAttribute->direction); + } + if ($dataBarAttribute->negativeBarBorderColorSameAsPositive) { + $extDataBarObj->setNegativeBarBorderColorSameAsPositive((bool) (string) $dataBarAttribute->negativeBarBorderColorSameAsPositive); + } + if ($dataBarAttribute->axisPosition) { + $extDataBarObj->setAxisPosition((string) $dataBarAttribute->axisPosition); + } + } + + private static function parseExtDataBarElementChildrenFromXml(ConditionalDataBarExtension $extDataBarObj, SimpleXMLElement $dataBarXml, $ns): void + { + if ($dataBarXml->borderColor) { + $extDataBarObj->setBorderColor((string) $dataBarXml->borderColor->attributes()['rgb']); + } + if ($dataBarXml->negativeFillColor) { + $extDataBarObj->setNegativeFillColor((string) $dataBarXml->negativeFillColor->attributes()['rgb']); + } + if ($dataBarXml->negativeBorderColor) { + $extDataBarObj->setNegativeBorderColor((string) $dataBarXml->negativeBorderColor->attributes()['rgb']); + } + if ($dataBarXml->axisColor) { + $axisColorAttr = $dataBarXml->axisColor->attributes(); + $extDataBarObj->setAxisColor((string) $axisColorAttr['rgb'], (string) $axisColorAttr['theme'], (string) $axisColorAttr['tint']); + } + $cfvoIndex = 0; + foreach ($dataBarXml->cfvo as $cfvo) { + $f = (string) $cfvo->children($ns['xm'])->f; + if ($cfvoIndex === 0) { + $extDataBarObj->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo->attributes()['type'], null, (empty($f) ? null : $f))); + } + if ($cfvoIndex === 1) { + $extDataBarObj->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject((string) $cfvo->attributes()['type'], null, (empty($f) ? null : $f))); + } + ++$cfvoIndex; + } + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @param mixed $id + */ + public function setId($id): self + { + $this->id = $id; + + return $this; + } + + public function getCfRule(): string + { + return $this->cfRule; + } + + public function setCfRule(string $cfRule): self + { + $this->cfRule = $cfRule; + + return $this; + } + + public function getDataBarExt(): ConditionalDataBarExtension + { + return $this->dataBar; + } + + public function setDataBarExt(ConditionalDataBarExtension $dataBar): self + { + $this->dataBar = $dataBar; + + return $this; + } + + public function getSqref(): string + { + return $this->sqref; + } + + public function setSqref(string $sqref): self + { + $this->sqref = $sqref; + + return $this; + } +} diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 8faa7ae2..7ad859ac 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -8,6 +8,8 @@ use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar; +use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; use PhpOffice\PhpSpreadsheet\Worksheet\SheetView; @@ -44,6 +46,7 @@ class Worksheet extends WriterPart $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing'); $objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main'); + $objWriter->writeAttribute('xmlns:xm', 'http://schemas.microsoft.com/office/excel/2006/main'); $objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); $objWriter->writeAttribute('mc:Ignorable', 'x14ac'); $objWriter->writeAttribute('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac'); @@ -114,6 +117,10 @@ class Worksheet extends WriterPart // AlternateContent $this->writeAlternateContent($objWriter, $pSheet); + // ConditionalFormattingRuleExtensionList + // (Must be inserted last. Not insert last, an Excel parse error will occur) + $this->writeExtLst($objWriter, $pSheet); + $objWriter->endElement(); // Return @@ -503,6 +510,94 @@ class Worksheet extends WriterPart } } + private static function writeExtConditionalFormattingElements(XMLWriter $objWriter, ConditionalFormattingRuleExtension $ruleExtension): void + { + $prefix = 'x14'; + $objWriter->startElementNs($prefix, 'conditionalFormatting', null); + + $objWriter->startElementNs($prefix, 'cfRule', null); + $objWriter->writeAttribute('type', $ruleExtension->getCfRule()); + $objWriter->writeAttribute('id', $ruleExtension->getId()); + $objWriter->startElementNs($prefix, 'dataBar', null); + $dataBar = $ruleExtension->getDataBarExt(); + foreach ($dataBar->getXmlAttributes() as $attrKey => $val) { + $objWriter->writeAttribute($attrKey, $val); + } + $minCfvo = $dataBar->getMinimumConditionalFormatValueObject(); + if ($minCfvo) { + $objWriter->startElementNs($prefix, 'cfvo', null); + $objWriter->writeAttribute('type', $minCfvo->getType()); + if ($minCfvo->getCellFormula()) { + $objWriter->writeElement('xm:f', $minCfvo->getCellFormula()); + } + $objWriter->endElement(); //end cfvo + } + + $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject(); + if ($maxCfvo) { + $objWriter->startElementNs($prefix, 'cfvo', null); + $objWriter->writeAttribute('type', $maxCfvo->getType()); + if ($maxCfvo->getCellFormula()) { + $objWriter->writeElement('xm:f', $maxCfvo->getCellFormula()); + } + $objWriter->endElement(); //end cfvo + } + + foreach ($dataBar->getXmlElements() as $elmKey => $elmAttr) { + $objWriter->startElementNs($prefix, $elmKey, null); + foreach ($elmAttr as $attrKey => $attrVal) { + $objWriter->writeAttribute($attrKey, $attrVal); + } + $objWriter->endElement(); //end elmKey + } + $objWriter->endElement(); //end dataBar + $objWriter->endElement(); //end cfRule + $objWriter->writeElement('xm:sqref', $ruleExtension->getSqref()); + $objWriter->endElement(); //end conditionalFormatting + } + + private static function writeDataBarElements(XMLWriter $objWriter, $dataBar): void + { + /** @var ConditionalDataBar $dataBar */ + if ($dataBar) { + $objWriter->startElement('dataBar'); + self::writeAttributeIf($objWriter, null !== $dataBar->getShowValue(), 'showValue', $dataBar->getShowValue() ? '1' : '0'); + + $minCfvo = $dataBar->getMinimumConditionalFormatValueObject(); + if ($minCfvo) { + $objWriter->startElement('cfvo'); + self::writeAttributeIf($objWriter, $minCfvo->getType(), 'type', (string) $minCfvo->getType()); + self::writeAttributeIf($objWriter, $minCfvo->getValue(), 'val', (string) $minCfvo->getValue()); + $objWriter->endElement(); + } + $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject(); + if ($maxCfvo) { + $objWriter->startElement('cfvo'); + self::writeAttributeIf($objWriter, $maxCfvo->getType(), 'type', (string) $maxCfvo->getType()); + self::writeAttributeIf($objWriter, $maxCfvo->getValue(), 'val', (string) $maxCfvo->getValue()); + $objWriter->endElement(); + } + if ($dataBar->getColor()) { + $objWriter->startElement('color'); + $objWriter->writeAttribute('rgb', $dataBar->getColor()); + $objWriter->endElement(); + } + $objWriter->endElement(); // end dataBar + + if ($dataBar->getConditionalFormattingRuleExt()) { + $objWriter->startElement('extLst'); + $extension = $dataBar->getConditionalFormattingRuleExt(); + $objWriter->startElement('ext'); + $objWriter->writeAttribute('uri', '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}'); + $objWriter->startElementNs('x14', 'id', null); + $objWriter->text($extension->getId()); + $objWriter->endElement(); + $objWriter->endElement(); + $objWriter->endElement(); //end extLst + } + } + } + /** * Write ConditionalFormatting. * @@ -529,7 +624,12 @@ class Worksheet extends WriterPart // cfRule $objWriter->startElement('cfRule'); $objWriter->writeAttribute('type', $conditional->getConditionType()); - $objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode())); + self::writeAttributeIf( + $objWriter, + ($conditional->getConditionType() != Conditional::CONDITION_DATABAR), + 'dxfId', + $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) + ); $objWriter->writeAttribute('priority', $id++); self::writeAttributeif( @@ -548,7 +648,10 @@ class Worksheet extends WriterPart self::writeOtherCondElements($objWriter, $conditional, $cellCoordinate); } - $objWriter->endElement(); + // + self::writeDataBarElements($objWriter, $conditional->getDataBar()); + + $objWriter->endElement(); //end cfRule $objWriter->endElement(); } @@ -1279,4 +1382,38 @@ class Worksheet extends WriterPart $objWriter->writeRaw($alternateContent); } } + + /** + * write + * only implementation conditionalFormattings. + * + * @url https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627 + */ + private function writeExtLst(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet): void + { + $conditionalFormattingRuleExtList = []; + foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) { + /** @var Conditional $conditional */ + foreach ($conditionalStyles as $conditional) { + $dataBar = $conditional->getDataBar(); + if ($dataBar && $dataBar->getConditionalFormattingRuleExt()) { + $conditionalFormattingRuleExtList[] = $dataBar->getConditionalFormattingRuleExt(); + } + } + } + + if (count($conditionalFormattingRuleExtList) > 0) { + $conditionalFormattingRuleExtNsPrefix = 'x14'; + $objWriter->startElement('extLst'); + $objWriter->startElement('ext'); + $objWriter->writeAttribute('uri', '{78C0D931-6437-407d-A8EE-F0AAD7539E65}'); + $objWriter->startElementNs($conditionalFormattingRuleExtNsPrefix, 'conditionalFormattings', null); + foreach ($conditionalFormattingRuleExtList as $extension) { + self::writeExtConditionalFormattingElements($objWriter, $extension); + } + $objWriter->endElement(); //end conditionalFormattings + $objWriter->endElement(); //end ext + $objWriter->endElement(); //end extLst + } + } } diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php new file mode 100644 index 00000000..60c5440b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php @@ -0,0 +1,325 @@ +load($filename); + $worksheet = $spreadsheet->getActiveSheet(); + + $this->pattern1Assertion($worksheet); + $this->pattern2Assertion($worksheet); + $this->pattern3Assertion($worksheet); + $this->pattern4Assertion($worksheet); + } + + public function testReloadXlsxConditionalFormattingDataBar(): void + { + // Make sure conditionals from existing file are maintained across save + $filename = 'tests/data/Reader/XLSX/conditionalFormattingDataBarTest.xlsx'; + $outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $reader = IOFactory::createReader('Xlsx'); + $spreadshee1 = $reader->load($filename); + $writer = IOFactory::createWriter($spreadshee1, 'Xlsx'); + $writer->save($outfile); + $spreadsheet = $reader->load($outfile); + unlink($outfile); + $worksheet = $spreadsheet->getActiveSheet(); + + $this->pattern1Assertion($worksheet); + $this->pattern2Assertion($worksheet); + $this->pattern3Assertion($worksheet); + $this->pattern4Assertion($worksheet); + } + + public function testNewXlsxConditionalFormattingDataBar(): void + { + // Make sure blanks/non-blanks added by PhpSpreadsheet are handled correctly + $outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $spreadshee1 = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); + $sheet = $spreadshee1->getActiveSheet(); + $sheet->setCellValue('A1', 1); + $sheet->setCellValue('A2', 2); + $sheet->setCellValue('A3', 3); + $sheet->setCellValue('A4', 4); + $sheet->setCellValue('A5', 5); + $cond1 = new Conditional(); + $cond1->setConditionType(Conditional::CONDITION_DATABAR); + $cond1->setDataBar(new ConditionalDataBar()); + $cond1->getDataBar() + ->setMinimumConditionalFormatValueObject(new ConditionalFormatValueObject('min')) + ->setMaximumConditionalFormatValueObject(new ConditionalFormatValueObject('max')) + ->setColor(Color::COLOR_GREEN); + $cond = [$cond1]; + $sheet->getStyle('A1:A5')->setConditionalStyles($cond); + $writer = IOFactory::createWriter($spreadshee1, 'Xlsx'); + $writer->save($outfile); + $reader = IOFactory::createReader('Xlsx'); + $spreadsheet = $reader->load($outfile); + unlink($outfile); + $worksheet = $spreadsheet->getActiveSheet(); + + $conditionalStyle = $worksheet->getConditionalStyles('A1:A5'); + self::assertNotEmpty($conditionalStyle); + /** @var Conditional $conditionalRule */ + $conditionalRule = $conditionalStyle[0]; + $conditions = $conditionalRule->getConditions(); + self::assertNotEmpty($conditions); + self::assertEquals(Conditional::CONDITION_DATABAR, $conditionalRule->getConditionType()); + self::assertNotEmpty($conditionalRule->getDataBar()); + + $dataBar = $conditionalRule->getDataBar(); + self::assertNotEmpty($dataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($dataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('min', $dataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('max', $dataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEquals(Color::COLOR_GREEN, $dataBar->getColor()); + } + + private function pattern1Assertion(Worksheet $worksheet): void + { + self::assertEquals( + "Type: Automatic, Automatic\nDirection: Automatic\nFills: Gradient\nAxis Position: Automatic", + $worksheet->getCell('A2')->getValue() + ); + + $conditionalStyle = $worksheet->getConditionalStyles('A3:A23'); + self::assertNotEmpty($conditionalStyle); + /** @var Conditional $conditionalRule */ + $conditionalRule = $conditionalStyle[0]; + $dataBar = $conditionalRule->getDataBar(); + + self::assertNotEmpty($dataBar); + self::assertEquals(Conditional::CONDITION_DATABAR, $conditionalRule->getConditionType()); + self::assertNotEmpty($dataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($dataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('min', $dataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('max', $dataBar->getMaximumConditionalFormatValueObject()->getType()); + + self::assertEquals('FF638EC6', $dataBar->getColor()); + self::assertNotEmpty($dataBar->getConditionalFormattingRuleExt()); + //ext + $rule1ext = $dataBar->getConditionalFormattingRuleExt(); + self::assertEquals('{72C64AE0-5CD9-164F-83D1-AB720F263E79}', $rule1ext->getId()); + self::assertEquals('dataBar', $rule1ext->getCfRule()); + self::assertEquals('A3:A23', $rule1ext->getSqref()); + $extDataBar = $rule1ext->getDataBarExt(); + self::assertNotEmpty($extDataBar); + $pattern1 = [ + 'minLength' => 0, + 'maxLength' => 100, + 'border' => true, + 'gradient' => null, + 'direction' => null, + 'axisPosition' => null, + 'negativeBarBorderColorSameAsPositive' => false, + 'borderColor' => 'FF638EC6', + 'negativeFillColor' => 'FFFF0000', + 'negativeBorderColor' => 'FFFF0000', + ]; + foreach ($pattern1 as $key => $value) { + $funcName = 'get' . ucwords($key); + self::assertEquals($value, $extDataBar->$funcName(), __METHOD__ . '::' . $funcName . ' function patten'); + } + + self::assertNotEmpty($extDataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($extDataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('autoMin', $extDataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('autoMax', $extDataBar->getMaximumConditionalFormatValueObject()->getType()); + + self::assertArrayHasKey('rgb', $extDataBar->getAxisColor()); + self::assertEquals('FF000000', $extDataBar->getAxisColor()['rgb']); + } + + private function pattern2Assertion(Worksheet $worksheet): void + { + self::assertEquals( + "Type: Number, Number\nValue: -5, 5\nDirection: Automatic\nFills: Solid\nAxis Position: Automatic", + $worksheet->getCell('B2')->getValue() + ); + + $conditionalStyle = $worksheet->getConditionalStyles('B3:B23'); + self::assertNotEmpty($conditionalStyle); + /** @var Conditional $conditionalRule */ + $conditionalRule = $conditionalStyle[0]; + $dataBar = $conditionalRule->getDataBar(); + + self::assertNotEmpty($dataBar); + self::assertEquals(Conditional::CONDITION_DATABAR, $conditionalRule->getConditionType()); + self::assertNotEmpty($dataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($dataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('num', $dataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('num', $dataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEquals('-5', $dataBar->getMinimumConditionalFormatValueObject()->getValue()); + self::assertEquals('5', $dataBar->getMaximumConditionalFormatValueObject()->getValue()); + self::assertEquals('FF63C384', $dataBar->getColor()); + self::assertNotEmpty($dataBar->getConditionalFormattingRuleExt()); + //ext + $rule1ext = $dataBar->getConditionalFormattingRuleExt(); + self::assertEquals('{98904F60-57F0-DF47-B480-691B20D325E3}', $rule1ext->getId()); + self::assertEquals('dataBar', $rule1ext->getCfRule()); + self::assertEquals('B3:B23', $rule1ext->getSqref()); + $extDataBar = $rule1ext->getDataBarExt(); + self::assertNotEmpty($extDataBar); + $pattern1 = [ + 'minLength' => 0, + 'maxLength' => 100, + 'border' => null, + 'gradient' => false, + 'direction' => null, + 'axisPosition' => null, + 'negativeBarBorderColorSameAsPositive' => null, + 'borderColor' => null, + 'negativeFillColor' => 'FFFF0000', + 'negativeBorderColor' => null, + ]; + foreach ($pattern1 as $key => $value) { + $funcName = 'get' . ucwords($key); + self::assertEquals($value, $extDataBar->$funcName(), $funcName . ' function patten'); + } + + self::assertNotEmpty($extDataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($extDataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('num', $extDataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('num', $extDataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEquals('-5', $extDataBar->getMinimumConditionalFormatValueObject()->getCellFormula()); + self::assertEquals('5', $extDataBar->getMaximumConditionalFormatValueObject()->getCellFormula()); + + self::assertArrayHasKey('rgb', $extDataBar->getAxisColor()); + self::assertEquals('FF000000', $extDataBar->getAxisColor()['rgb']); + } + + private function pattern3Assertion(Worksheet $worksheet): void + { + self::assertEquals( + "Type: Automatic, Automatic\nDirection: rightToLeft\nFills: Solid\nAxis Position: None", + $worksheet->getCell('C2')->getValue() + ); + + $conditionalStyle = $worksheet->getConditionalStyles('C3:C23'); + self::assertNotEmpty($conditionalStyle); + /** @var Conditional $conditionalRule */ + $conditionalRule = $conditionalStyle[0]; + $dataBar = $conditionalRule->getDataBar(); + + self::assertNotEmpty($dataBar); + self::assertEquals(Conditional::CONDITION_DATABAR, $conditionalRule->getConditionType()); + self::assertNotEmpty($dataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($dataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('min', $dataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('max', $dataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEmpty($dataBar->getMinimumConditionalFormatValueObject()->getValue()); + self::assertEmpty($dataBar->getMaximumConditionalFormatValueObject()->getValue()); + self::assertEquals('FFFF555A', $dataBar->getColor()); + self::assertNotEmpty($dataBar->getConditionalFormattingRuleExt()); + + //ext + $rule1ext = $dataBar->getConditionalFormattingRuleExt(); + self::assertEquals('{453C04BA-7ABD-8548-8A17-D9CFD2BDABE9}', $rule1ext->getId()); + self::assertEquals('dataBar', $rule1ext->getCfRule()); + self::assertEquals('C3:C23', $rule1ext->getSqref()); + $extDataBar = $rule1ext->getDataBarExt(); + self::assertNotEmpty($extDataBar); + $pattern1 = [ + 'minLength' => 0, + 'maxLength' => 100, + 'border' => null, + 'gradient' => false, + 'direction' => 'rightToLeft', + 'axisPosition' => 'none', + 'negativeBarBorderColorSameAsPositive' => null, + 'borderColor' => null, + 'negativeFillColor' => 'FFFF0000', + 'negativeBorderColor' => null, + ]; + foreach ($pattern1 as $key => $value) { + $funcName = 'get' . ucwords($key); + self::assertEquals($value, $extDataBar->$funcName(), $funcName . ' function patten'); + } + + self::assertNotEmpty($extDataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($extDataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('autoMin', $extDataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('autoMax', $extDataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEmpty($extDataBar->getMinimumConditionalFormatValueObject()->getCellFormula()); + self::assertEmpty($extDataBar->getMaximumConditionalFormatValueObject()->getCellFormula()); + + self::assertArrayHasKey('rgb', $extDataBar->getAxisColor()); + self::assertEmpty($extDataBar->getAxisColor()['rgb']); + } + + private function pattern4Assertion(Worksheet $worksheet): void + { + self::assertEquals( + "type: formula, formula\nValue: =2+3, =10+10\nDirection: leftToRight\nShowDataBarOnly\nFills: Solid\nBorder: Solid\nAxis Position: Midpoint", + $worksheet->getCell('D2')->getValue() + ); + + $conditionalStyle = $worksheet->getConditionalStyles('D3:D23'); + self::assertNotEmpty($conditionalStyle); + /** @var Conditional $conditionalRule */ + $conditionalRule = $conditionalStyle[0]; + $dataBar = $conditionalRule->getDataBar(); + + self::assertNotEmpty($dataBar); + self::assertEquals(Conditional::CONDITION_DATABAR, $conditionalRule->getConditionType()); + + self::assertTrue($dataBar->getShowValue()); + self::assertNotEmpty($dataBar->getMinimumConditionalFormatValueObject()); + self::assertNotEmpty($dataBar->getMaximumConditionalFormatValueObject()); + self::assertEquals('formula', $dataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('formula', $dataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEquals('3+2', $dataBar->getMinimumConditionalFormatValueObject()->getValue()); + self::assertEquals('10+10', $dataBar->getMaximumConditionalFormatValueObject()->getValue()); + self::assertEquals('FFFF555A', $dataBar->getColor()); + self::assertNotEmpty($dataBar->getConditionalFormattingRuleExt()); + + //ext + $rule1ext = $dataBar->getConditionalFormattingRuleExt(); + self::assertEquals('{6C1E066A-E240-3D4A-98F8-8CC218B0DFD2}', $rule1ext->getId()); + self::assertEquals('dataBar', $rule1ext->getCfRule()); + self::assertEquals('D3:D23', $rule1ext->getSqref()); + $extDataBar = $rule1ext->getDataBarExt(); + self::assertNotEmpty($extDataBar); + $pattern1 = [ + 'minLength' => 0, + 'maxLength' => 100, + 'border' => true, + 'gradient' => false, + 'direction' => 'leftToRight', + 'axisPosition' => 'middle', + 'negativeBarBorderColorSameAsPositive' => null, + 'borderColor' => 'FF000000', + 'negativeFillColor' => 'FFFF0000', + 'negativeBorderColor' => null, + ]; + foreach ($pattern1 as $key => $value) { + $funcName = 'get' . ucwords($key); + self::assertEquals($value, $extDataBar->$funcName(), $funcName . ' function patten'); + } + + self::assertNotEmpty($extDataBar->getMaximumConditionalFormatValueObject()); + self::assertNotEmpty($extDataBar->getMinimumConditionalFormatValueObject()); + self::assertEquals('formula', $extDataBar->getMinimumConditionalFormatValueObject()->getType()); + self::assertEquals('formula', $extDataBar->getMaximumConditionalFormatValueObject()->getType()); + self::assertEquals('3+2', $extDataBar->getMinimumConditionalFormatValueObject()->getCellFormula()); + self::assertEquals('10+10', $extDataBar->getMaximumConditionalFormatValueObject()->getCellFormula()); + + self::assertArrayHasKey('rgb', $extDataBar->getAxisColor()); + self::assertEquals('FF000000', $extDataBar->getAxisColor()['rgb']); + } +} diff --git a/tests/data/Reader/XLSX/conditionalFormattingDataBarTest.xlsx b/tests/data/Reader/XLSX/conditionalFormattingDataBarTest.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f1434329f001a75621ca07f9e1ae7ec8b2a084db GIT binary patch literal 10443 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 Znk$uL;hskq06>2J_&u{e7tL?q{vS<{lUx7* literal 0 HcmV?d00001 From 24fb8e61ae7010e6094f8c04a01e8872bcfc95f7 Mon Sep 17 00:00:00 2001 From: SheetJSDev Date: Fri, 29 Jan 2021 11:14:38 -0500 Subject: [PATCH 018/187] formatAsDate strip language metadata (#1618) * Revert "Fix cant get right format chinese date format error" This reverts commit 8c58385d6c103d23f6a5b3d1899a5e7cc8f66e92. * formatAsDate strip language metadata (fixes #1616) Co-authored-by: Mark Baker --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Style/NumberFormat.php | 2 +- tests/data/Style/NumberFormatDates.php | 27 +++++++++-------------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cefe1590..24ddedc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Changed - Updated the CONVERT() function to support all current MS Excel categories and Units of Measure. +- `formatAsDate` correctly matches language metadata, reverting c55272e ### Deprecated diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index 0b761bd3..9a0acb6f 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -469,7 +469,7 @@ class NumberFormat extends Supervisor // general syntax: [$-] // language info is in hexadecimal // strip off chinese part like [DBNum1][$-804] - $format = preg_replace('/^(\[[0-9A-Za-z]*\])*(\[\$[A-Z]*-[0-9A-F]*\])/i', '', $format); + $format = preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format); // OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case; // but we don't want to change any quoted strings diff --git a/tests/data/Style/NumberFormatDates.php b/tests/data/Style/NumberFormatDates.php index 9e476042..331a080c 100644 --- a/tests/data/Style/NumberFormatDates.php +++ b/tests/data/Style/NumberFormatDates.php @@ -36,22 +36,6 @@ return [ 22269.0625, '"y-m-d "yyyy-mm-dd" h:m:s "hh:mm:ss', ], - // Chinese date format - [ - '1960年12月19日', - 22269.0625, - '[DBNum1][$-804]yyyy"年"m"月"d"日";@', - ], - [ - '1960年12月', - 22269.0625, - '[DBNum1][$-804]yyyy"年"m"月";@', - ], - [ - '12月19日', - 22269.0625, - '[DBNum1][$-804]m"月"d"日";@', - ], [ '07:35:00 AM', 43270.315972222, @@ -77,4 +61,15 @@ return [ 1.1354166666667, '[h]:mm', ], + [ + '19331018', + 12345.6789, + '[DBNum4][$-804]yyyymmdd;@', + ], + // Technically should be 19331018 + [ + '19331018', + 12345.6789, + '[DBNum3][$-zh-CN]yyyymmdd;@', + ], ]; From cd2f260db18f96a9e41fd0d6b066786c28412173 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 29 Jan 2021 17:31:28 +0100 Subject: [PATCH 019/187] Additional method call/return typing --- composer.json | 2 +- composer.lock | 1916 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 1309 insertions(+), 609 deletions(-) diff --git a/composer.json b/composer.json index 0fffd510..483c3828 100644 --- a/composer.json +++ b/composer.json @@ -63,7 +63,7 @@ }, "require-dev": { "dompdf/dompdf": "^0.8.5", - "friendsofphp/php-cs-fixer": "^2.16||^2.18", + "friendsofphp/php-cs-fixer": "^2.18", "jpgraph/jpgraph": "^4.0", "mpdf/mpdf": "^8.0", "phpcompatibility/php-compatibility": "^9.3", diff --git a/composer.lock b/composer.lock index a1fb99b7..bbb9ff7e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "458fe4e974b469230da589a8781d1e0e", + "content-hash": "8a567f9030fc836c175557d0430f1057", "packages": [ { "name": "ezyang/htmlpurifier", @@ -119,6 +119,16 @@ "stream", "zip" ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/master" + }, + "funding": [ + { + "url": "https://opencollective.com/zipstream", + "type": "open_collective" + } + ], "time": "2020-05-30T13:11:16+00:00" }, { @@ -214,24 +224,28 @@ "complex", "mathematics" ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/PHP8" + }, "time": "2020-08-26T10:42:07+00:00" }, { "name": "markbaker/matrix", - "version": "2.0.0", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/MarkBaker/PHPMatrix.git", - "reference": "9567d9c4c519fbe40de01dbd1e4469dbbb66f46a" + "reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/9567d9c4c519fbe40de01dbd1e4469dbbb66f46a", - "reference": "9567d9c4c519fbe40de01dbd1e4469dbbb66f46a", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/361c0f545c3172ee26c3d596a0aa03f0cef65e6a", + "reference": "361c0f545c3172ee26c3d596a0aa03f0cef65e6a", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", @@ -249,22 +263,22 @@ "Matrix\\": "classes/src/" }, "files": [ - "classes/src/functions/adjoint.php", - "classes/src/functions/antidiagonal.php", - "classes/src/functions/cofactors.php", - "classes/src/functions/determinant.php", - "classes/src/functions/diagonal.php", - "classes/src/functions/identity.php", - "classes/src/functions/inverse.php", - "classes/src/functions/minors.php", - "classes/src/functions/trace.php", - "classes/src/functions/transpose.php", - "classes/src/operations/add.php", - "classes/src/operations/directsum.php", - "classes/src/operations/subtract.php", - "classes/src/operations/multiply.php", - "classes/src/operations/divideby.php", - "classes/src/operations/divideinto.php" + "classes/src/Functions/adjoint.php", + "classes/src/Functions/antidiagonal.php", + "classes/src/Functions/cofactors.php", + "classes/src/Functions/determinant.php", + "classes/src/Functions/diagonal.php", + "classes/src/Functions/identity.php", + "classes/src/Functions/inverse.php", + "classes/src/Functions/minors.php", + "classes/src/Functions/trace.php", + "classes/src/Functions/transpose.php", + "classes/src/Operations/add.php", + "classes/src/Operations/directsum.php", + "classes/src/Operations/subtract.php", + "classes/src/Operations/multiply.php", + "classes/src/Operations/divideby.php", + "classes/src/Operations/divideinto.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -284,20 +298,24 @@ "matrix", "vector" ], - "time": "2020-08-28T17:11:00+00:00" + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/2.1.2" + }, + "time": "2021-01-23T16:37:31+00:00" }, { "name": "myclabs/php-enum", - "version": "1.7.6", + "version": "1.7.7", "source": { "type": "git", "url": "https://github.com/myclabs/php-enum.git", - "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c" + "reference": "d178027d1e679832db9f38248fcc7200647dc2b7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/php-enum/zipball/5f36467c7a87e20fbdc51e524fd8f9d1de80187c", - "reference": "5f36467c7a87e20fbdc51e524fd8f9d1de80187c", + "url": "https://api.github.com/repos/myclabs/php-enum/zipball/d178027d1e679832db9f38248fcc7200647dc2b7", + "reference": "d178027d1e679832db9f38248fcc7200647dc2b7", "shasum": "" }, "require": { @@ -330,7 +348,21 @@ "keywords": [ "enum" ], - "time": "2020-02-14T08:15:52+00:00" + "support": { + "issues": "https://github.com/myclabs/php-enum/issues", + "source": "https://github.com/myclabs/php-enum/tree/1.7.7" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/php-enum", + "type": "tidelift" + } + ], + "time": "2020-11-14T18:14:52+00:00" }, { "name": "psr/http-client", @@ -379,6 +411,9 @@ "psr", "psr-18" ], + "support": { + "source": "https://github.com/php-fig/http-client/tree/master" + }, "time": "2020-06-29T06:28:15+00:00" }, { @@ -431,6 +466,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/master" + }, "time": "2019-04-30T12:38:16+00:00" }, { @@ -481,6 +519,9 @@ "request", "response" ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, "time": "2016-08-06T14:39:51+00:00" }, { @@ -529,24 +570,27 @@ "psr-16", "simple-cache" ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, "time": "2017-10-23T01:57:42+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", - "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-mbstring": "For best performance" @@ -554,7 +598,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -592,6 +636,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -606,34 +653,35 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T16:49:33+00:00" } ], "packages-dev": [ { "name": "composer/semver", - "version": "1.7.1", + "version": "3.2.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "38276325bd896f90dfcfe30029aa5db40df387a7" + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/38276325bd896f90dfcfe30029aa5db40df387a7", - "reference": "38276325bd896f90dfcfe30029aa5db40df387a7", + "url": "https://api.github.com/repos/composer/semver/zipball/a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", + "reference": "a02fdf930a3c1c3ed3a49b5f63859c0c20e10464", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0" + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5" + "phpstan/phpstan": "^0.12.54", + "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-main": "3.x-dev" } }, "autoload": { @@ -669,6 +717,11 @@ "validation", "versioning" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.2.4" + }, "funding": [ { "url": "https://packagist.com", @@ -683,20 +736,20 @@ "type": "tidelift" } ], - "time": "2020-09-27T13:13:07+00:00" + "time": "2020-11-13T08:59:24+00:00" }, { "name": "composer/xdebug-handler", - "version": "1.4.3", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ebd27a9866ae8254e873866f795491f02418c5a5" + "reference": "f28d44c286812c714741478d968104c5e604a1d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ebd27a9866ae8254e873866f795491f02418c5a5", - "reference": "ebd27a9866ae8254e873866f795491f02418c5a5", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", + "reference": "f28d44c286812c714741478d968104c5e604a1d4", "shasum": "" }, "require": { @@ -727,6 +780,11 @@ "Xdebug", "performance" ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" + }, "funding": [ { "url": "https://packagist.com", @@ -741,20 +799,20 @@ "type": "tidelift" } ], - "time": "2020-08-19T10:27:58+00:00" + "time": "2020-11-13T08:04:11+00:00" }, { "name": "doctrine/annotations", - "version": "1.10.4", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "bfe91e31984e2ba76df1c1339681770401ec262f" + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/bfe91e31984e2ba76df1c1339681770401ec262f", - "reference": "bfe91e31984e2ba76df1c1339681770401ec262f", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", "shasum": "" }, "require": { @@ -764,13 +822,14 @@ }, "require-dev": { "doctrine/cache": "1.*", + "doctrine/coding-standard": "^6.0 || ^8.1", "phpstan/phpstan": "^0.12.20", "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9.x-dev" + "dev-master": "1.11.x-dev" } }, "autoload": { @@ -805,46 +864,45 @@ } ], "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", "keywords": [ "annotations", "docblock", "parser" ], - "time": "2020-08-10T19:35:50+00:00" + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.11.1" + }, + "time": "2020-10-26T10:28:16+00:00" }, { "name": "doctrine/instantiator", - "version": "1.3.1", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", - "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^6.0", + "doctrine/coding-standard": "^8.0", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" @@ -858,7 +916,7 @@ { "name": "Marco Pivetta", "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "homepage": "https://ocramius.github.io/" } ], "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", @@ -867,7 +925,25 @@ "constructor", "instantiate" ], - "time": "2020-05-29T17:27:14+00:00" + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" }, { "name": "doctrine/lexer", @@ -929,6 +1005,24 @@ "parser", "php" ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], "time": "2020-05-25T17:44:05+00:00" }, { @@ -997,31 +1091,35 @@ ], "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", "homepage": "https://github.com/dompdf/dompdf", + "support": { + "issues": "https://github.com/dompdf/dompdf/issues", + "source": "https://github.com/dompdf/dompdf/tree/master" + }, "time": "2020-08-30T22:54:22+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v2.16.4", + "version": "v2.18.2", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "1023c3458137ab052f6ff1e09621a721bfdeca13" + "reference": "18f8c9d184ba777380794a389fabc179896ba913" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/1023c3458137ab052f6ff1e09621a721bfdeca13", - "reference": "1023c3458137ab052f6ff1e09621a721bfdeca13", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/18f8c9d184ba777380794a389fabc179896ba913", + "reference": "18f8c9d184ba777380794a389fabc179896ba913", "shasum": "" }, "require": { - "composer/semver": "^1.4", + "composer/semver": "^1.4 || ^2.0 || ^3.0", "composer/xdebug-handler": "^1.2", "doctrine/annotations": "^1.2", "ext-json": "*", "ext-tokenizer": "*", - "php": "^5.6 || ^7.0", + "php": "^5.6 || ^7.0 || ^8.0", "php-cs-fixer/diff": "^1.3", - "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "symfony/console": "^3.4.43 || ^4.1.6 || ^5.0", "symfony/event-dispatcher": "^3.0 || ^4.0 || ^5.0", "symfony/filesystem": "^3.0 || ^4.0 || ^5.0", "symfony/finder": "^3.0 || ^4.0 || ^5.0", @@ -1032,17 +1130,19 @@ "symfony/stopwatch": "^3.0 || ^4.0 || ^5.0" }, "require-dev": { - "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0", "justinrainbow/json-schema": "^5.0", - "keradus/cli-executor": "^1.2", + "keradus/cli-executor": "^1.4", "mikey179/vfsstream": "^1.6", - "php-coveralls/php-coveralls": "^2.1", + "php-coveralls/php-coveralls": "^2.4.2", "php-cs-fixer/accessible-object": "^1.0", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.1", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.1", - "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.1", - "phpunitgoodpractices/traits": "^1.8", - "symfony/phpunit-bridge": "^5.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.13 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "sanmai/phpunit-legacy-adapter": "^6.4 || ^8.2.1", + "symfony/phpunit-bridge": "^5.2.1", "symfony/yaml": "^3.0 || ^4.0 || ^5.0" }, "suggest": { @@ -1088,7 +1188,17 @@ } ], "description": "A tool to automatically fix PHP code style", - "time": "2020-06-27T23:57:46+00:00" + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.2" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-01-26T00:22:21+00:00" }, { "name": "jpgraph/jpgraph", @@ -1128,36 +1238,40 @@ "jpgraph", "pie" ], + "support": { + "issues": "https://github.com/ztec/JpGraph/issues", + "source": "https://github.com/ztec/JpGraph/tree/4.x" + }, "abandoned": true, "time": "2017-02-23T09:44:15+00:00" }, { "name": "mpdf/mpdf", - "version": "v8.0.7", + "version": "v8.0.10", "source": { "type": "git", "url": "https://github.com/mpdf/mpdf.git", - "reference": "7daf07f15334ed59a276bd52131dcca48794cdbd" + "reference": "1333a962cd2f7ae1a127b7534b7734b58179186f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/7daf07f15334ed59a276bd52131dcca48794cdbd", - "reference": "7daf07f15334ed59a276bd52131dcca48794cdbd", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/1333a962cd2f7ae1a127b7534b7734b58179186f", + "reference": "1333a962cd2f7ae1a127b7534b7734b58179186f", "shasum": "" }, "require": { "ext-gd": "*", "ext-mbstring": "*", "myclabs/deep-copy": "^1.7", - "paragonie/random_compat": "^1.4|^2.0|9.99.99", - "php": "^5.6 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": "^5.6 || ^7.0 || ~8.0.0", "psr/log": "^1.0", "setasign/fpdi": "^2.1" }, "require-dev": { - "mockery/mockery": "^0.9.5", - "mpdf/qrcode": "^1.0.0", - "phpunit/phpunit": "^5.0", + "mockery/mockery": "^1.3.0", + "mpdf/qrcode": "^1.1.0", + "phpunit/phpunit": "^5.7", "squizlabs/php_codesniffer": "^3.5.0", "tracy/tracy": "^2.4" }, @@ -1167,11 +1281,6 @@ "ext-zlib": "Needed for compression of embedded resources, such as fonts" }, "type": "library", - "extra": { - "branch-alias": { - "dev-development": "7.x-dev" - } - }, "autoload": { "psr-4": { "Mpdf\\": "src/" @@ -1198,26 +1307,31 @@ "php", "utf-8" ], + "support": { + "docs": "http://mpdf.github.io", + "issues": "https://github.com/mpdf/mpdf/issues", + "source": "https://github.com/mpdf/mpdf" + }, "funding": [ { "url": "https://www.paypal.me/mpdf", "type": "custom" } ], - "time": "2020-07-15T09:48:00+00:00" + "time": "2021-01-08T14:59:28+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.10.1", + "version": "1.10.2", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5" + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", - "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", "shasum": "" }, "require": { @@ -1252,30 +1366,90 @@ "object", "object graph" ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, "funding": [ { "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", "type": "tidelift" } ], - "time": "2020-06-29T13:22:24+00:00" + "time": "2020-11-13T09:40:50+00:00" }, { - "name": "paragonie/random_compat", - "version": "v9.99.99", + "name": "nikic/php-parser", + "version": "v4.10.4", "source": { "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", - "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", + "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", "shasum": "" }, "require": { - "php": "^7" + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" + }, + "time": "2020-12-20T10:01:03+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" }, "require-dev": { "phpunit/phpunit": "4.*|5.*", @@ -1303,32 +1477,38 @@ "pseudorandom", "random" ], - "time": "2018-07-02T15:55:56+00:00" + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" }, { "name": "phar-io/manifest", - "version": "1.0.3", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", "shasum": "" }, "require": { "ext-dom": "*", "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1358,24 +1538,28 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2018-07-08T19:23:20+00:00" + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, + "time": "2020-06-27T14:33:11+00:00" }, { "name": "phar-io/version", - "version": "2.0.1", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", + "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -1405,7 +1589,11 @@ } ], "description": "Library for handling version information and constraints", - "time": "2018-07-08T19:19:57+00:00" + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.0.4" + }, + "time": "2020-12-13T23:18:30+00:00" }, { "name": "phenx/php-font-lib", @@ -1442,6 +1630,10 @@ ], "description": "A library to read, parse, export and make subsets of different types of font files.", "homepage": "https://github.com/PhenX/php-font-lib", + "support": { + "issues": "https://github.com/PhenX/php-font-lib/issues", + "source": "https://github.com/PhenX/php-font-lib/tree/0.5.2" + }, "time": "2020-03-08T15:31:32+00:00" }, { @@ -1482,6 +1674,10 @@ ], "description": "A library to read, parse and export to PDF SVG files.", "homepage": "https://github.com/PhenX/php-svg-lib", + "support": { + "issues": "https://github.com/PhenX/php-svg-lib/issues", + "source": "https://github.com/PhenX/php-svg-lib/tree/master" + }, "time": "2019-09-11T20:02:13+00:00" }, { @@ -1533,6 +1729,10 @@ "keywords": [ "diff" ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v1.3.1" + }, "time": "2020-10-14T08:39:05+00:00" }, { @@ -1591,6 +1791,10 @@ "phpcs", "standards" ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", + "source": "https://github.com/PHPCompatibility/PHPCompatibility" + }, "time": "2019-12-27T09:44:58+00:00" }, { @@ -1640,6 +1844,10 @@ "reflection", "static analysis" ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, "time": "2020-06-27T09:03:43+00:00" }, { @@ -1692,6 +1900,10 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + }, "time": "2020-09-03T19:13:55+00:00" }, { @@ -1737,20 +1949,24 @@ } ], "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + }, "time": "2020-09-17T18:55:26+00:00" }, { "name": "phpspec/prophecy", - "version": "1.12.1", + "version": "1.12.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d" + "reference": "245710e971a030f42e08f4912863805570f23d39" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/8ce87516be71aae9b956f81906aaf0338e0d8a2d", - "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", + "reference": "245710e971a030f42e08f4912863805570f23d39", "shasum": "" }, "require": { @@ -1762,7 +1978,7 @@ }, "require-dev": { "phpspec/phpspec": "^6.0", - "phpunit/phpunit": "^8.0 || ^9.0 <9.3" + "phpunit/phpunit": "^8.0 || ^9.0" }, "type": "library", "extra": { @@ -1800,44 +2016,52 @@ "spy", "stub" ], - "time": "2020-09-29T09:10:42+00:00" + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/1.12.2" + }, + "time": "2020-12-19T10:15:11+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "7.0.10", + "version": "9.2.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf" + "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f1884187926fbb755a9aaf0b3836ad3165b478bf", - "reference": "f1884187926fbb755a9aaf0b3836ad3165b478bf", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1", + "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": "^7.2", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.1.1", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^4.2.2", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1.3" + "nikic/php-parser": "^4.10.2", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^8.2.2" + "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-xdebug": "^2.7.2" + "ext-pcov": "*", + "ext-xdebug": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "7.0-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -1863,32 +2087,42 @@ "testing", "xunit" ], - "time": "2019-11-20T13:55:58+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:44:49+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "2.0.2", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "050bedf145a257b1ff02746c31894800e5122946" + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", - "reference": "050bedf145a257b1ff02746c31894800e5122946", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", + "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1913,26 +2147,107 @@ "filesystem", "iterator" ], - "time": "2018-09-13T20:33:42+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:57:25+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -1954,32 +2269,42 @@ "keywords": [ "template" ], - "time": "2015-06-21T13:50:34+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" }, { "name": "phpunit/php-timer", - "version": "2.1.2", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2003,105 +2328,69 @@ "keywords": [ "timer" ], - "time": "2019-06-07T04:22:29+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ + "funding": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "url": "https://github.com/sebastianbergmann", + "type": "github" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2019-09-17T06:23:10+00:00" + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/phpunit", - "version": "8.5.8", + "version": "9.5.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "34c18baa6a44f1d1fbf0338907139e9dce95b997" + "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/34c18baa6a44f1d1fbf0338907139e9dce95b997", - "reference": "34c18baa6a44f1d1fbf0338907139e9dce95b997", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7bdf4085de85a825f4424eae52c99a1cec2f360", + "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.2.0", + "doctrine/instantiator": "^1.3.1", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.9.1", - "phar-io/manifest": "^1.0.3", - "phar-io/version": "^2.0.1", - "php": "^7.2", - "phpspec/prophecy": "^1.8.1", - "phpunit/php-code-coverage": "^7.0.7", - "phpunit/php-file-iterator": "^2.0.2", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1.2", - "sebastian/comparator": "^3.0.2", - "sebastian/diff": "^3.0.2", - "sebastian/environment": "^4.2.2", - "sebastian/exporter": "^3.1.1", - "sebastian/global-state": "^3.0.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0.1", - "sebastian/type": "^1.1.3", - "sebastian/version": "^2.0.1" + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.1", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpspec/prophecy": "^1.12.1", + "phpunit/php-code-coverage": "^9.2.3", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.5", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.3", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^2.3", + "sebastian/version": "^3.0.2" }, "require-dev": { - "ext-pdo": "*" + "ext-pdo": "*", + "phpspec/prophecy-phpunit": "^2.0.1" }, "suggest": { "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0.0" + "ext-xdebug": "*" }, "bin": [ "phpunit" @@ -2109,12 +2398,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "8.5-dev" + "dev-master": "9.5-dev" } }, "autoload": { "classmap": [ "src/" + ], + "files": [ + "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2135,7 +2427,21 @@ "testing", "xunit" ], - "time": "2020-06-22T07:06:58+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.1" + }, + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-01-17T07:42:25+00:00" }, { "name": "psr/container", @@ -2184,6 +2490,10 @@ "container-interop", "psr" ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, "time": "2017-02-14T16:28:37+00:00" }, { @@ -2230,6 +2540,10 @@ "psr", "psr-14" ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, "time": "2019-01-08T18:20:26+00:00" }, { @@ -2277,6 +2591,9 @@ "psr", "psr-3" ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.3" + }, "time": "2020-03-23T09:12:05+00:00" }, { @@ -2322,32 +2639,148 @@ "parser", "stylesheet" ], + "support": { + "issues": "https://github.com/sabberworm/PHP-CSS-Parser/issues", + "source": "https://github.com/sabberworm/PHP-CSS-Parser/tree/8.3.1" + }, "time": "2020-06-01T09:10:00+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", + "name": "sebastian/cli-parser", "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" } }, "autoload": { @@ -2367,34 +2800,44 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "3.0.2", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + "reference": "55f4261989e546dc112258c7a75935a81a7ce382" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", + "reference": "55f4261989e546dc112258c7a75935a81a7ce382", "shasum": "" }, "require": { - "php": "^7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2407,6 +2850,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -2418,10 +2865,6 @@ { "name": "Bernhard Schussek", "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" } ], "description": "Provides the functionality to compare PHP values for equality", @@ -2431,33 +2874,43 @@ "compare", "equality" ], - "time": "2018-07-12T15:12:46+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:49:45+00:00" }, { - "name": "sebastian/diff", - "version": "3.0.2", + "name": "sebastian/complexity", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", "shasum": "" }, "require": { - "php": "^7.1" + "nikic/php-parser": "^4.7", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -2471,12 +2924,69 @@ ], "authors": [ { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:52:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], "description": "Diff implementation", @@ -2487,27 +2997,37 @@ "unidiff", "unified diff" ], - "time": "2019-02-04T06:01:07+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" }, { "name": "sebastian/environment", - "version": "4.2.3", + "version": "5.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" + "reference": "388b6ced16caa751030f6a69e588299fa09200ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", + "reference": "388b6ced16caa751030f6a69e588299fa09200ac", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -2515,7 +3035,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -2540,34 +3060,44 @@ "environment", "hhvm" ], - "time": "2019-11-20T08:46:58+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:52:38+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.2", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -2607,30 +3137,40 @@ "export", "exporter" ], - "time": "2019-09-14T09:02:43+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:24:23+00:00" }, { "name": "sebastian/global-state", - "version": "3.0.0", + "version": "5.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4" + "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", - "reference": "edf8a461cf1d4005f19fb0b6b8b95a9f7fa0adc4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", + "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", "shasum": "" }, "require": { - "php": "^7.2", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^8.0" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -2638,7 +3178,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -2661,34 +3201,101 @@ "keywords": [ "global state" ], - "time": "2019-02-01T05:30:01+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T15:55:19+00:00" }, { - "name": "sebastian/object-enumerator", - "version": "3.0.3", + "name": "sebastian/lines-of-code", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "nikic/php-parser": "^4.6", + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" } }, "autoload": { @@ -2708,122 +3315,37 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.1", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "shasum": "" - }, - "require": { - "php": "^7.1" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -2846,34 +3368,162 @@ "email": "sebastian@phpunit.de" } ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2018-10-04T04:07:39+00:00" + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" }, { - "name": "sebastian/type", - "version": "1.1.3", + "name": "sebastian/recursion-context", + "version": "4.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/3aaaa15fa71d27650d62a948be022fe3b48541a3", - "reference": "3aaaa15fa71d27650d62a948be022fe3b48541a3", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", + "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", "shasum": "" }, "require": { - "php": "^7.2" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:17:30+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "2.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" } }, "autoload": { @@ -2894,29 +3544,39 @@ ], "description": "Collection of value objects that represent the types of the PHP type system", "homepage": "https://github.com/sebastianbergmann/type", - "time": "2019-07-02T08:10:15+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:18:59+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2937,25 +3597,35 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { "name": "setasign/fpdi", - "version": "v2.3.4", + "version": "v2.3.5", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "2b5fb811c04f937ef257ef3f798cebeded33c136" + "reference": "f2246c8669bd25834f5c264425eb0e250d7a9312" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/2b5fb811c04f937ef257ef3f798cebeded33c136", - "reference": "2b5fb811c04f937ef257ef3f798cebeded33c136", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/f2246c8669bd25834f5c264425eb0e250d7a9312", + "reference": "f2246c8669bd25834f5c264425eb0e250d7a9312", "shasum": "" }, "require": { "ext-zlib": "*", - "php": "^5.6 || ^7.0" + "php": "^5.6 || ^7.0 || ^8.0" }, "conflict": { "setasign/tfpdf": "<1.31" @@ -2999,26 +3669,30 @@ "fpdi", "pdf" ], + "support": { + "issues": "https://github.com/Setasign/FPDI/issues", + "source": "https://github.com/Setasign/FPDI/tree/v2.3.5" + }, "funding": [ { "url": "https://tidelift.com/funding/github/packagist/setasign/fpdi", "type": "tidelift" } ], - "time": "2020-08-27T06:55:47+00:00" + "time": "2020-12-03T13:40:03+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.5.6", + "version": "3.5.8", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "e97627871a7eab2f70e59166072a6b767d5834e0" + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/e97627871a7eab2f70e59166072a6b767d5834e0", - "reference": "e97627871a7eab2f70e59166072a6b767d5834e0", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", + "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", "shasum": "" }, "require": { @@ -3056,20 +3730,25 @@ "phpcs", "standards" ], - "time": "2020-08-10T04:50:15+00:00" + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2020-10-23T02:01:07+00:00" }, { "name": "symfony/console", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ae789a8a2ad189ce7e8216942cdb9b77319f5eb8" + "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ae789a8a2ad189ce7e8216942cdb9b77319f5eb8", - "reference": "ae789a8a2ad189ce7e8216942cdb9b77319f5eb8", + "url": "https://api.github.com/repos/symfony/console/zipball/d62ec79478b55036f65e2602e282822b8eaaff0a", + "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a", "shasum": "" }, "require": { @@ -3106,11 +3785,6 @@ "symfony/process": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Console\\": "" @@ -3133,8 +3807,17 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3149,7 +3832,7 @@ "type": "tidelift" } ], - "time": "2020-10-07T15:23:00+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3199,6 +3882,9 @@ ], "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/master" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3217,16 +3903,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "d5de97d6af175a9e8131c546db054ca32842dd0f" + "reference": "4f9760f8074978ad82e2ce854dff79a71fe45367" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d5de97d6af175a9e8131c546db054ca32842dd0f", - "reference": "d5de97d6af175a9e8131c546db054ca32842dd0f", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4f9760f8074978ad82e2ce854dff79a71fe45367", + "reference": "4f9760f8074978ad82e2ce854dff79a71fe45367", "shasum": "" }, "require": { @@ -3257,11 +3943,6 @@ "symfony/http-kernel": "" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\EventDispatcher\\": "" @@ -3284,8 +3965,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3300,7 +3984,7 @@ "type": "tidelift" } ], - "time": "2020-09-18T14:27:32+00:00" + "time": "2021-01-27T10:36:42+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -3362,6 +4046,9 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.2.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3380,16 +4067,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "1a8697545a8d87b9f2f6b1d32414199cc5e20aae" + "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/1a8697545a8d87b9f2f6b1d32414199cc5e20aae", - "reference": "1a8697545a8d87b9f2f6b1d32414199cc5e20aae", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", + "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", "shasum": "" }, "require": { @@ -3397,11 +4084,6 @@ "symfony/polyfill-ctype": "~1.8" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" @@ -3424,8 +4106,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3440,31 +4125,26 @@ "type": "tidelift" } ], - "time": "2020-09-27T14:02:37+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/finder", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "2c3ba7ad6884e6c4451ce2340e2dc23f6fa3e0d8" + "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/2c3ba7ad6884e6c4451ce2340e2dc23f6fa3e0d8", - "reference": "2c3ba7ad6884e6c4451ce2340e2dc23f6fa3e0d8", + "url": "https://api.github.com/repos/symfony/finder/zipball/196f45723b5e618bf0e23b97e96d11652696ea9e", + "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e", "shasum": "" }, "require": { "php": ">=7.2.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Finder\\": "" @@ -3487,8 +4167,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Finder Component", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3503,33 +4186,29 @@ "type": "tidelift" } ], - "time": "2020-09-02T16:23:27+00:00" + "time": "2021-01-27T10:01:46+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "4c7e155bf7d93ea4ba3824d5a14476694a5278dd" + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4c7e155bf7d93ea4ba3824d5a14476694a5278dd", - "reference": "4c7e155bf7d93ea4ba3824d5a14476694a5278dd", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", + "reference": "5d0f633f9bbfcf7ec642a2b5037268e61b0a62ce", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php73": "~1.0", "symfony/polyfill-php80": "^1.15" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\OptionsResolver\\": "" @@ -3552,13 +4231,16 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony OptionsResolver Component", + "description": "Provides an improved replacement for the array_replace PHP function", "homepage": "https://symfony.com", "keywords": [ "config", "configuration", "options" ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3573,24 +4255,24 @@ "type": "tidelift" } ], - "time": "2020-09-27T03:44:28+00:00" + "time": "2021-01-27T12:56:27+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", - "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/c6c942b1ac76c82448322025e084cadc56048b4e", + "reference": "c6c942b1ac76c82448322025e084cadc56048b4e", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-ctype": "For best performance" @@ -3598,7 +4280,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3635,6 +4317,9 @@ "polyfill", "portable" ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3649,24 +4334,24 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5" + "reference": "267a9adeb8ecb8071040a740930e077cdfb987af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b740103edbdcc39602239ee8860f0f45a8eb9aa5", - "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/267a9adeb8ecb8071040a740930e077cdfb987af", + "reference": "267a9adeb8ecb8071040a740930e077cdfb987af", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" @@ -3674,7 +4359,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3713,6 +4398,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3727,24 +4415,24 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e" + "reference": "6e971c891537eb617a00bb07a43d182a6915faba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", - "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", + "reference": "6e971c891537eb617a00bb07a43d182a6915faba", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "suggest": { "ext-intl": "For best performance" @@ -3752,7 +4440,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3794,6 +4482,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3808,47 +4499,35 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T17:09:11+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.18.1", + "version": "v1.20.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3" + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", - "reference": "0dd93f2c578bdc9c72697eaa5f1dd25644e618d3", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", - "php": ">=5.3.3" + "php": ">=7.1" }, - "type": "library", + "type": "metapackage", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.20-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -3871,6 +4550,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3885,29 +4567,29 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2020-10-23T14:02:19+00:00" }, { "name": "symfony/polyfill-php72", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "639447d008615574653fb3bc60d1986d7172eaae" + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/639447d008615574653fb3bc60d1986d7172eaae", - "reference": "639447d008615574653fb3bc60d1986d7172eaae", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", + "reference": "cc6e6f9b39fe8075b3dabfbaf5b5f645ae1340c9", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -3944,6 +4626,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -3958,29 +4643,29 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca" + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca", - "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", + "reference": "a678b42e92f86eca04b7fa4c0f6f19d097fb69e2", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4020,6 +4705,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -4034,29 +4722,29 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.18.1", + "version": "v1.22.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", - "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dc3063ba22c2a1fd2f45ed856374d79114998f91", + "reference": "dc3063ba22c2a1fd2f45ed856374d79114998f91", "shasum": "" }, "require": { - "php": ">=7.0.8" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.18-dev" + "dev-main": "1.22-dev" }, "thanks": { "name": "symfony/polyfill", @@ -4100,6 +4788,9 @@ "portable", "shim" ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -4114,20 +4805,20 @@ "type": "tidelift" } ], - "time": "2020-07-14T12:35:20+00:00" + "time": "2021-01-07T16:49:33+00:00" }, { "name": "symfony/process", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d3a2e64866169586502f0cd9cab69135ad12cee9" + "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d3a2e64866169586502f0cd9cab69135ad12cee9", - "reference": "d3a2e64866169586502f0cd9cab69135ad12cee9", + "url": "https://api.github.com/repos/symfony/process/zipball/313a38f09c77fbcdc1d223e57d368cea76a2fd2f", + "reference": "313a38f09c77fbcdc1d223e57d368cea76a2fd2f", "shasum": "" }, "require": { @@ -4135,11 +4826,6 @@ "symfony/polyfill-php80": "^1.15" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Process\\": "" @@ -4162,8 +4848,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Process Component", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -4178,7 +4867,7 @@ "type": "tidelift" } ], - "time": "2020-09-02T16:23:27+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/service-contracts", @@ -4240,6 +4929,9 @@ "interoperability", "standards" ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/master" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -4258,16 +4950,16 @@ }, { "name": "symfony/stopwatch", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "0f7c58cf81dbb5dd67d423a89d577524a2ec0323" + "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/0f7c58cf81dbb5dd67d423a89d577524a2ec0323", - "reference": "0f7c58cf81dbb5dd67d423a89d577524a2ec0323", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b12274acfab9d9850c52583d136a24398cdf1a0c", + "reference": "b12274acfab9d9850c52583d136a24398cdf1a0c", "shasum": "" }, "require": { @@ -4275,11 +4967,6 @@ "symfony/service-contracts": "^1.0|^2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" @@ -4302,8 +4989,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Stopwatch Component", + "description": "Provides a way to profile code", "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -4318,20 +5008,20 @@ "type": "tidelift" } ], - "time": "2020-05-20T17:43:50+00:00" + "time": "2021-01-27T10:15:41+00:00" }, { "name": "symfony/string", - "version": "v5.1.7", + "version": "v5.2.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "4a9afe9d07bac506f75bcee8ed3ce76da5a9343e" + "reference": "c95468897f408dd0aca2ff582074423dd0455122" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/4a9afe9d07bac506f75bcee8ed3ce76da5a9343e", - "reference": "4a9afe9d07bac506f75bcee8ed3ce76da5a9343e", + "url": "https://api.github.com/repos/symfony/string/zipball/c95468897f408dd0aca2ff582074423dd0455122", + "reference": "c95468897f408dd0aca2ff582074423dd0455122", "shasum": "" }, "require": { @@ -4349,11 +5039,6 @@ "symfony/var-exporter": "^4.4|^5.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, "autoload": { "psr-4": { "Symfony\\Component\\String\\": "" @@ -4379,7 +5064,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony String component", + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", "homepage": "https://symfony.com", "keywords": [ "grapheme", @@ -4389,6 +5074,9 @@ "utf-8", "utf8" ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.2.2" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -4403,7 +5091,7 @@ "type": "tidelift" } ], - "time": "2020-09-15T12:23:47+00:00" + "time": "2021-01-25T15:14:59+00:00" }, { "name": "tecnickcom/tcpdf", @@ -4465,6 +5153,10 @@ "pdf417", "qrcode" ], + "support": { + "issues": "https://github.com/tecnickcom/TCPDF/issues", + "source": "https://github.com/tecnickcom/TCPDF/tree/6.3.5" + }, "time": "2020-02-14T14:20:12+00:00" }, { @@ -4505,6 +5197,10 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/master" + }, "funding": [ { "url": "https://github.com/theseer", @@ -4518,12 +5214,12 @@ "version": "1.9.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", + "url": "https://github.com/webmozarts/assert.git", "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, @@ -4560,6 +5256,10 @@ "check", "validate" ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.9.1" + }, "time": "2020-07-08T17:02:28+00:00" } ], From 8ab02883bef8672112c748a4005afa09105e3297 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 29 Jan 2021 17:40:51 +0100 Subject: [PATCH 020/187] Composer fixes --- .github/workflows/main.yml | 2 +- src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php | 4 ++-- src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a01892ae..5f68a4ff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,7 +44,7 @@ jobs: echo "::set-output name=flags::--ignore-platform-reqs" - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }} + run: composer update --no-progress --prefer-dist --optimize-autoloader ${{ steps.composer-lock.outputs.flags }} - name: Setup problem matchers for PHP run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" diff --git a/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php index 4aecff73..6db17c28 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php @@ -240,11 +240,11 @@ class LUDecomposition /** * Solve A*X = B. * - * @param mixed $B a Matrix with as many rows as A and any number of columns + * @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($B) + public function solve(Matrix $B) { if ($B->getRowDimension() == $this->m) { if ($this->isNonsingular()) { diff --git a/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php index 3bb8a10e..027706c1 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php @@ -205,7 +205,7 @@ class QRDecomposition * * @return Matrix matrix that minimizes the two norm of Q*R*X-B */ - public function solve($B) + public function solve(Matrix $B) { if ($B->getRowDimension() == $this->m) { if ($this->isFullRank()) { From 03ab6305e6178bddd0d59bafcace529d31a80f19 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 29 Jan 2021 17:47:37 +0100 Subject: [PATCH 021/187] PHPCS Fixes --- src/PhpSpreadsheet/Reader/Xlsx.php | 6 +++--- src/PhpSpreadsheet/Shared/JAMA/Matrix.php | 2 +- src/PhpSpreadsheet/Shared/OLE/PPS.php | 2 +- src/PhpSpreadsheet/Writer/Xls/Workbook.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 4222b954..eafa36b5 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -532,7 +532,7 @@ class Xlsx extends BaseReader $excel->addCellXf($objStyle); } - foreach (isset($xmlStyles->cellStyleXfs->xf) ? $xmlStyles->cellStyleXfs->xf : [] as $xf) { + foreach ($xmlStyles->cellStyleXfs->xf ?? [] as $xf) { $numFmt = NumberFormat::FORMAT_GENERAL; if ($numFmts && $xf['numFmtId']) { $tmpNumFmt = self::getArrayItem($numFmts->xpath("sml:numFmt[@numFmtId=$xf[numFmtId]]")); @@ -1148,7 +1148,7 @@ class Xlsx extends BaseReader $shadow->setDistance(Drawing::EMUToPixels(self::getArrayItem($outerShdw->attributes(), 'dist'))); $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir'))); $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn')); - $clr = isset($outerShdw->srgbClr) ? $outerShdw->srgbClr : $outerShdw->prstClr; + $clr = $outerShdw->srgbClr ?? $outerShdw->prstClr; $shadow->getColor()->setRGB(self::getArrayItem($clr->attributes(), 'val')); $shadow->setAlpha(self::getArrayItem($clr->alpha->attributes(), 'val') / 1000); } @@ -1201,7 +1201,7 @@ class Xlsx extends BaseReader $shadow->setDistance(Drawing::EMUToPixels(self::getArrayItem($outerShdw->attributes(), 'dist'))); $shadow->setDirection(Drawing::angleToDegrees(self::getArrayItem($outerShdw->attributes(), 'dir'))); $shadow->setAlignment((string) self::getArrayItem($outerShdw->attributes(), 'algn')); - $clr = isset($outerShdw->srgbClr) ? $outerShdw->srgbClr : $outerShdw->prstClr; + $clr = $outerShdw->srgbClr ?? $outerShdw->prstClr; $shadow->getColor()->setRGB(self::getArrayItem($clr->attributes(), 'val')); $shadow->setAlpha(self::getArrayItem($clr->alpha->attributes(), 'val') / 1000); } diff --git a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php index a5cb6de0..5182993c 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php +++ b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php @@ -1164,7 +1164,7 @@ class Matrix * * @return Matrix ... Solution if A is square, least squares solution otherwise */ - public function solve($B) + public function solve(self $B) { if ($this->m == $this->n) { $LU = new LUDecomposition($this); diff --git a/src/PhpSpreadsheet/Shared/OLE/PPS.php b/src/PhpSpreadsheet/Shared/OLE/PPS.php index cf764d0b..a90f193b 100644 --- a/src/PhpSpreadsheet/Shared/OLE/PPS.php +++ b/src/PhpSpreadsheet/Shared/OLE/PPS.php @@ -189,7 +189,7 @@ class PPS . "\x00\x00\x00\x00" // 100 . OLE::localDateToOLE($this->Time1st) // 108 . OLE::localDateToOLE($this->Time2nd) // 116 - . pack('V', isset($this->startBlock) ? $this->startBlock : 0) // 120 + . pack('V', $this->startBlock ?? 0) // 120 . pack('V', $this->Size) // 124 . pack('V', 0); // 128 diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index f752bce6..2b4895f0 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -757,7 +757,7 @@ class Workbook extends BIFFwriter * * @param string $name * @param string $sheetIndex 1-based sheet index the defined name applies to. 0 = global - * @param integer[][] $rangeBounds range boundaries + * @param int[][] $rangeBounds range boundaries * @param bool $isHidden * * @return string Complete binary record data From 4092da0525e70e8bebb0b6c38ca67263002b914f Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 29 Jan 2021 22:21:55 +0100 Subject: [PATCH 022/187] Additional unit tests for statistical functions, with a fix to ordering for RANK() (#1813) * Additional unit tests for statistical functions, with a fix to ordering for RANK() --- .../Calculation/Statistical.php | 8 ++- .../Functions/Statistical/PercentRankTest.php | 34 ++++++++++++ .../Functions/Statistical/PercentileTest.php | 31 +++++++++++ .../Functions/Statistical/QuartileTest.php | 31 +++++++++++ .../Functions/Statistical/RankTest.php | 34 ++++++++++++ .../Calculation/Statistical/PERCENTILE.php | 28 ++++++++++ .../Calculation/Statistical/PERCENTRANK.php | 52 +++++++++++++++++++ .../data/Calculation/Statistical/QUARTILE.php | 40 ++++++++++++++ tests/data/Calculation/Statistical/RANK.php | 31 +++++++++++ 9 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php create mode 100644 tests/data/Calculation/Statistical/PERCENTILE.php create mode 100644 tests/data/Calculation/Statistical/PERCENTRANK.php create mode 100644 tests/data/Calculation/Statistical/QUARTILE.php create mode 100644 tests/data/Calculation/Statistical/RANK.php diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 19f40f2d..52234f5a 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2868,6 +2868,9 @@ class Statistical * PERCENTRANK. * * Returns the rank of a value in a data set as a percentage of the data set. + * Note that the returned rank is simply rounded to the appropriate significant digits, + * rather than floored (as MS Excel), so value 3 for a value set of 1, 2, 3, 4 will return + * 0.667 rather than 0.666 * * @param float[] $valueSet An array of, or a reference to, a list of numbers * @param int $value the number whose rank you want to find @@ -3037,10 +3040,11 @@ class Statistical } if ($order == 0) { - rsort($valueSet, SORT_NUMERIC); - } else { sort($valueSet, SORT_NUMERIC); + } else { + rsort($valueSet, SORT_NUMERIC); } + $pos = array_search($value, $valueSet); if ($pos === false) { return Functions::NA(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php new file mode 100644 index 00000000..71eff7ac --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php @@ -0,0 +1,34 @@ + Date: Fri, 29 Jan 2021 23:23:29 +0100 Subject: [PATCH 023/187] Unhappy path unit tests (#1814) * Unhappy path unit tests * Fix unhappy error for BETADIST and BETAINV min/max range --- src/PhpSpreadsheet/Calculation/Statistical.php | 16 ++++++++-------- tests/data/Calculation/Statistical/BETADIST.php | 4 ++++ tests/data/Calculation/Statistical/BETAINV.php | 4 ++++ .../data/Calculation/Statistical/PERCENTILE.php | 8 ++++++++ .../data/Calculation/Statistical/PERCENTRANK.php | 16 ++++++++++++++++ tests/data/Calculation/Statistical/QUARTILE.php | 8 ++++++++ tests/data/Calculation/Statistical/RANK.php | 10 ++++++++++ 7 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 52234f5a..6c1d6c7b 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -765,14 +765,14 @@ class Statistical $rMax = Functions::flattenSingleValue($rMax); if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { - if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) { - return Functions::NAN(); - } if ($rMin > $rMax) { $tmp = $rMin; $rMin = $rMax; $rMax = $tmp; } + if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) { + return Functions::NAN(); + } $value -= $rMin; $value /= ($rMax - $rMin); @@ -804,14 +804,14 @@ class Statistical $rMax = Functions::flattenSingleValue($rMax); if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { - if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { - return Functions::NAN(); - } if ($rMin > $rMax) { $tmp = $rMin; $rMin = $rMax; $rMax = $tmp; } + if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { + return Functions::NAN(); + } $a = 0; $b = 2; @@ -3000,11 +3000,11 @@ class Statistical public static function QUARTILE(...$args) { $aArgs = Functions::flattenArray($args); + $entry = array_pop($aArgs); // Calculate - $entry = floor(array_pop($aArgs)); - if ((is_numeric($entry)) && (!is_string($entry))) { + $entry = floor($entry); $entry /= 4; if (($entry < 0) || ($entry > 1)) { return Functions::NAN(); diff --git a/tests/data/Calculation/Statistical/BETADIST.php b/tests/data/Calculation/Statistical/BETADIST.php index f489429c..9fbecaaa 100644 --- a/tests/data/Calculation/Statistical/BETADIST.php +++ b/tests/data/Calculation/Statistical/BETADIST.php @@ -13,6 +13,10 @@ return [ 0.960370937542, 3, 7.5, 9, 1, 4, ], + [ + 0.960370937542, + 3, 7.5, 9, 4, 1, + ], [ 0.598190307617, 7.5, 8, 9, 5, 10, diff --git a/tests/data/Calculation/Statistical/BETAINV.php b/tests/data/Calculation/Statistical/BETAINV.php index d62c1c35..5afe14cb 100644 --- a/tests/data/Calculation/Statistical/BETAINV.php +++ b/tests/data/Calculation/Statistical/BETAINV.php @@ -9,6 +9,10 @@ return [ 2.164759759129, 0.3, 7.5, 9, 1, 4, ], + [ + 2.164759759129, + 0.3, 7.5, 9, 4, 1, + ], [ 7.761240188783, 0.75, 8, 9, 5, 10, diff --git a/tests/data/Calculation/Statistical/PERCENTILE.php b/tests/data/Calculation/Statistical/PERCENTILE.php index b5d60eca..121e49c0 100644 --- a/tests/data/Calculation/Statistical/PERCENTILE.php +++ b/tests/data/Calculation/Statistical/PERCENTILE.php @@ -25,4 +25,12 @@ return [ 48.4, [10.5, 7.2, 200, 5.4, 8.1, 0.8], ], + [ + '#NUM!', + [1, 2, 3, 4, -0.3], + ], + [ + '#VALUE!', + [1, 2, 3, 4, 'NaN'], + ], ]; diff --git a/tests/data/Calculation/Statistical/PERCENTRANK.php b/tests/data/Calculation/Statistical/PERCENTRANK.php index 86bf75f9..3ab019ac 100644 --- a/tests/data/Calculation/Statistical/PERCENTRANK.php +++ b/tests/data/Calculation/Statistical/PERCENTRANK.php @@ -49,4 +49,20 @@ return [ [13, 12, 11, 8, 4, 3, 2, 1, 1, 1], 5, ], + [ + 0.67, + [1, 'Deux', 2, 'Uno', 3, 4], + 3, + 2, + ], + [ + '#NUM!', + ['A', 'B', 'C', 'D'], + 'E', + ], + [ + '#N/A', + [1, 2, 3, 4], + 5, + ], ]; diff --git a/tests/data/Calculation/Statistical/QUARTILE.php b/tests/data/Calculation/Statistical/QUARTILE.php index f46ae97b..80b2bf09 100644 --- a/tests/data/Calculation/Statistical/QUARTILE.php +++ b/tests/data/Calculation/Statistical/QUARTILE.php @@ -37,4 +37,12 @@ return [ 9.25, [7, 8, 9, 10, 3], ], + [ + '#NUM!', + [7, 8, 9, 10, 5], + ], + [ + '#VALUE!', + [7, 8, 9, 10, 'X'], + ], ]; diff --git a/tests/data/Calculation/Statistical/RANK.php b/tests/data/Calculation/Statistical/RANK.php index b8f74e06..0640bb43 100644 --- a/tests/data/Calculation/Statistical/RANK.php +++ b/tests/data/Calculation/Statistical/RANK.php @@ -28,4 +28,14 @@ return [ 7.2, [10.5, 7.2, 200, 5.4, 8.1], ], + [ + 3, + 3.5, + [7, 3.5, 'ONE', 'UNO', 3.5, 1, 2], + ], + [ + '#N/A', + 1.5, + [7, 3.5, 3.5, 1, 2], + ], ]; From 41c8a4f1b419c3812db5f9da86bb5c702d7be892 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 30 Jan 2021 18:45:31 +0100 Subject: [PATCH 024/187] Additional unit tests for previously untested financial functions (#1815) * Additional unit tests for previously untested financial functions, and some additions to follow untested paths * Start splitting Financial function tests out from the large FinancialTests class into individual test classes for each function --- src/PhpSpreadsheet/Calculation/Financial.php | 6 +- .../Calculation/FinancialTest.php | 128 ------------------ .../Functions/Financial/AmorDegRcTest.php | 31 +++++ .../Functions/Financial/AmorLincTest.php | 31 +++++ .../Functions/Financial/CoupDayBsTest.php | 31 +++++ .../Functions/Financial/CoupDaysNcTest.php | 31 +++++ .../Functions/Financial/CoupDaysTest.php | 31 +++++ .../Functions/Financial/CoupNcdTest.php | 31 +++++ .../Functions/Financial/CoupNumTest.php | 31 +++++ .../Functions/Financial/CoupPcdTest.php | 31 +++++ .../Functions/Financial/PriceMatTest.php | 31 +++++ .../Functions/Financial/ReceivedTest.php | 31 +++++ .../Functions/Financial/TBillEqTest.php | 31 +++++ .../Functions/Financial/TBillPriceTest.php | 31 +++++ .../Functions/Financial/TBillYieldTest.php | 31 +++++ .../Functions/Financial/YieldDiscTest.php | 31 +++++ .../Functions/Financial/YieldMatTest.php | 31 +++++ .../data/Calculation/Financial/AMORDEGRC.php | 28 ++-- tests/data/Calculation/Financial/AMORLINC.php | 28 ++-- tests/data/Calculation/Financial/PRICEMAT.php | 16 +++ tests/data/Calculation/Financial/RECEIVED.php | 16 +++ tests/data/Calculation/Financial/TBILLEQ.php | 20 +++ .../data/Calculation/Financial/TBILLPRICE.php | 20 +++ .../data/Calculation/Financial/TBILLYIELD.php | 12 ++ .../data/Calculation/Financial/YIELDDISC.php | 12 ++ tests/data/Calculation/Financial/YIELDMAT.php | 12 ++ 26 files changed, 604 insertions(+), 159 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php create mode 100644 tests/data/Calculation/Financial/PRICEMAT.php create mode 100644 tests/data/Calculation/Financial/RECEIVED.php create mode 100644 tests/data/Calculation/Financial/TBILLEQ.php create mode 100644 tests/data/Calculation/Financial/TBILLPRICE.php create mode 100644 tests/data/Calculation/Financial/TBILLYIELD.php create mode 100644 tests/data/Calculation/Financial/YIELDDISC.php create mode 100644 tests/data/Calculation/Financial/YIELDMAT.php diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 5a908aa5..728167f4 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -2037,7 +2037,7 @@ class Financial return Functions::VALUE(); } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { + if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { ++$maturity; $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity) * 360; } else { @@ -2076,7 +2076,7 @@ class Financial return Functions::NAN(); } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { + if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { ++$maturity; $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity) * 360; if (!is_numeric($daysBetweenSettlementAndMaturity)) { @@ -2087,7 +2087,7 @@ class Financial $daysBetweenSettlementAndMaturity = (DateTime::getDateValue($maturity) - DateTime::getDateValue($settlement)); } - if ($daysBetweenSettlementAndMaturity > 360) { + if ($daysBetweenSettlementAndMaturity > self::daysPerYear(DateTime::YEAR($maturity), 1)) { return Functions::NAN(); } diff --git a/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php b/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php index e80ef35b..d6135a46 100644 --- a/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php @@ -13,134 +13,6 @@ class FinancialTest extends TestCase Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); } - /** - * @dataProvider providerAMORDEGRC - * - * @param mixed $expectedResult - */ - public function testAMORDEGRC($expectedResult, ...$args): void - { - $result = Financial::AMORDEGRC(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerAMORDEGRC() - { - return require 'tests/data/Calculation/Financial/AMORDEGRC.php'; - } - - /** - * @dataProvider providerAMORLINC - * - * @param mixed $expectedResult - */ - public function testAMORLINC($expectedResult, ...$args): void - { - $result = Financial::AMORLINC(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerAMORLINC() - { - return require 'tests/data/Calculation/Financial/AMORLINC.php'; - } - - /** - * @dataProvider providerCOUPDAYBS - * - * @param mixed $expectedResult - */ - public function testCOUPDAYBS($expectedResult, ...$args): void - { - $result = Financial::COUPDAYBS(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerCOUPDAYBS() - { - return require 'tests/data/Calculation/Financial/COUPDAYBS.php'; - } - - /** - * @dataProvider providerCOUPDAYS - * - * @param mixed $expectedResult - */ - public function testCOUPDAYS($expectedResult, ...$args): void - { - $result = Financial::COUPDAYS(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerCOUPDAYS() - { - return require 'tests/data/Calculation/Financial/COUPDAYS.php'; - } - - /** - * @dataProvider providerCOUPDAYSNC - * - * @param mixed $expectedResult - */ - public function testCOUPDAYSNC($expectedResult, ...$args): void - { - $result = Financial::COUPDAYSNC(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerCOUPDAYSNC() - { - return require 'tests/data/Calculation/Financial/COUPDAYSNC.php'; - } - - /** - * @dataProvider providerCOUPNCD - * - * @param mixed $expectedResult - */ - public function testCOUPNCD($expectedResult, ...$args): void - { - $result = Financial::COUPNCD(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerCOUPNCD() - { - return require 'tests/data/Calculation/Financial/COUPNCD.php'; - } - - /** - * @dataProvider providerCOUPNUM - * - * @param mixed $expectedResult - */ - public function testCOUPNUM($expectedResult, ...$args): void - { - $result = Financial::COUPNUM(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerCOUPNUM() - { - return require 'tests/data/Calculation/Financial/COUPNUM.php'; - } - - /** - * @dataProvider providerCOUPPCD - * - * @param mixed $expectedResult - */ - public function testCOUPPCD($expectedResult, ...$args): void - { - $result = Financial::COUPPCD(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerCOUPPCD() - { - return require 'tests/data/Calculation/Financial/COUPPCD.php'; - } - /** * @dataProvider providerCUMIPMT * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php new file mode 100644 index 00000000..5d0cb8ef --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php @@ -0,0 +1,31 @@ + Date: Sun, 31 Jan 2021 15:09:56 +0100 Subject: [PATCH 025/187] Extract remaining Excel function unit tests into separate test classes for each function (#1817) * Extract remaining Financial function unit tests into separate test classes for each function This makes it easier to manage unit tests if they are individual files rather than all in a single file It also provides a stepping stone toward making it easier to test Excel functions when Excel errors no longer return a string, but an actual Excel exception that can be handled more cleanly --- src/PhpSpreadsheet/Shared/OLE.php | 3 +- src/PhpSpreadsheet/Worksheet/AutoFilter.php | 4 +- .../Calculation/FinancialTest.php | 500 ------------------ .../Functions/Financial/CumIpmtTest.php | 31 ++ .../Functions/Financial/CumPrincTest.php | 31 ++ .../Functions/Financial/DbTest.php | 31 ++ .../Functions/Financial/DdbTest.php | 31 ++ .../Functions/Financial/DiscTest.php | 31 ++ .../Functions/Financial/DollarDeTest.php | 31 ++ .../Functions/Financial/DollarFrTest.php | 31 ++ .../Functions/Financial/EffectTest.php | 31 ++ .../Functions/Financial/FvScheduleTest.php | 31 ++ .../Functions/Financial/FvTest.php | 31 ++ .../Functions/Financial/IPmtTest.php | 31 ++ .../Functions/Financial/IntRateTest.php | 31 ++ .../Functions/Financial/IrrTest.php | 31 ++ .../Functions/Financial/IsPmtTest.php | 31 ++ .../Functions/Financial/MirrTest.php | 31 ++ .../Functions/Financial/NPerTest.php | 31 ++ .../Functions/Financial/NominalTest.php | 31 ++ .../Functions/Financial/NpvTest.php | 31 ++ .../Functions/Financial/PDurationTest.php | 31 ++ .../Functions/Financial/PriceDiscTest.php | 31 ++ .../Functions/Financial/PriceTest.php | 50 ++ .../Functions/Financial/PvTest.php | 31 ++ .../Functions/Financial/RateTest.php | 31 ++ .../Functions/Financial/RriTest.php | 31 ++ .../Functions/Financial/SlnTest.php | 31 ++ .../Functions/Financial/SydTest.php | 31 ++ .../Functions/Financial/XNpvTest.php | 40 ++ .../Functions/Financial/XirrTest.php | 40 ++ 31 files changed, 910 insertions(+), 502 deletions(-) delete mode 100644 tests/PhpSpreadsheetTests/Calculation/FinancialTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php diff --git a/src/PhpSpreadsheet/Shared/OLE.php b/src/PhpSpreadsheet/Shared/OLE.php index d380995c..1c745bdb 100644 --- a/src/PhpSpreadsheet/Shared/OLE.php +++ b/src/PhpSpreadsheet/Shared/OLE.php @@ -227,7 +227,8 @@ class OLE // in OLE_ChainedBlockStream::stream_open(). // Object is removed from self::$instances in OLE_Stream::close(). $GLOBALS['_OLE_INSTANCES'][] = $this; - $instanceId = end(array_keys($GLOBALS['_OLE_INSTANCES'])); + $keys = array_keys($GLOBALS['_OLE_INSTANCES']); + $instanceId = end($keys); $path = 'ole-chainedblockstream://oleInstanceId=' . $instanceId; if ($blockIdOrPps instanceof OLE\PPS) { diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/src/PhpSpreadsheet/Worksheet/AutoFilter.php index c2ded195..4c33eb37 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -595,7 +595,9 @@ class AutoFilter sort($dataValues); } - return array_pop(array_slice($dataValues, 0, $ruleValue)); + $slice = array_slice($dataValues, 0, $ruleValue); + + return array_pop($slice); } /** diff --git a/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php b/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php deleted file mode 100644 index d6135a46..00000000 --- a/tests/PhpSpreadsheetTests/Calculation/FinancialTest.php +++ /dev/null @@ -1,500 +0,0 @@ - 0.999999 && $frac < 1.000001) { - $result = $expectedResult; - } - } - } - self::assertEquals($expectedResult, $result, $message); - } - - public function providerXIRR() - { - return require 'tests/data/Calculation/Financial/XIRR.php'; - } - - /** - * @dataProvider providerXNPV - * - * @param mixed $expectedResult - * @param mixed $message - */ - public function testXNPV($expectedResult, $message, ...$args): void - { - $result = Financial::XNPV(...$args); - if (is_numeric($result) && is_numeric($expectedResult)) { - if ($expectedResult != 0) { - $frac = $result / $expectedResult; - if ($frac > 0.999999 && $frac < 1.000001) { - $result = $expectedResult; - } - } - } - self::assertEquals($expectedResult, $result, $message); - } - - public function providerXNPV() - { - return require 'tests/data/Calculation/Financial/XNPV.php'; - } - - /** - * @dataProvider providerPDURATION - * - * @param mixed $expectedResult - */ - public function testPDURATION($expectedResult, array $args): void - { - $result = Financial::PDURATION(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerPDURATION() - { - return require 'tests/data/Calculation/Financial/PDURATION.php'; - } - - /** - * @dataProvider providerRRI - * - * @param mixed $expectedResult - */ - public function testRRI($expectedResult, array $args): void - { - $result = Financial::RRI(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerRRI() - { - return require 'tests/data/Calculation/Financial/RRI.php'; - } - - /** - * @dataProvider providerSLN - * - * @param mixed $expectedResult - */ - public function testSLN($expectedResult, array $args): void - { - $result = Financial::SLN(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerSLN() - { - return require 'tests/data/Calculation/Financial/SLN.php'; - } - - /** - * @dataProvider providerSYD - * - * @param mixed $expectedResult - */ - public function testSYD($expectedResult, array $args): void - { - $result = Financial::SYD(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); - } - - public function providerSYD() - { - return require 'tests/data/Calculation/Financial/SYD.php'; - } -} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php new file mode 100644 index 00000000..ff82bcbc --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php @@ -0,0 +1,31 @@ + 0.999999 && $frac < 1.000001) { + $result = $expectedResult; + } + } + } + self::assertEquals($expectedResult, $result, $message); + } + + public function providerXNPV() + { + return require 'tests/data/Calculation/Financial/XNPV.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php new file mode 100644 index 00000000..042ef298 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php @@ -0,0 +1,40 @@ + 0.999999 && $frac < 1.000001) { + $result = $expectedResult; + } + } + } + self::assertEquals($expectedResult, $result, $message); + } + + public function providerXIRR() + { + return require 'tests/data/Calculation/Financial/XIRR.php'; + } +} From 18abae7245041cda6189d88b75f0bd45178d8f9b Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 31 Jan 2021 16:42:17 +0100 Subject: [PATCH 026/187] Additional statistical unit tests (#1818) --- .../Statistical/NegBinomDistTest.php | 31 ++++++++++++++++ .../Functions/Statistical/PoissonTest.php | 31 ++++++++++++++++ tests/data/Calculation/MathTrig/FLOOR.php | 5 +++ tests/data/Calculation/MathTrig/FLOORMATH.php | 5 +++ .../Calculation/MathTrig/FLOORPRECISE.php | 5 +++ .../Calculation/Statistical/NEGBINOMDIST.php | 36 +++++++++++++++++++ tests/data/Calculation/Statistical/PERMUT.php | 8 +++++ .../data/Calculation/Statistical/POISSON.php | 28 +++++++++++++++ 8 files changed, 149 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php create mode 100644 tests/data/Calculation/Statistical/NEGBINOMDIST.php create mode 100644 tests/data/Calculation/Statistical/POISSON.php diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php new file mode 100644 index 00000000..9c082da7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php @@ -0,0 +1,31 @@ + Date: Sun, 31 Jan 2021 08:12:25 -0800 Subject: [PATCH 027/187] Inherited Scrutinizer Recommendations - 1 of 3 (#1806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make DefinedNames Samples Consistent With Other Samples (#1707) All other Samples write to temporary directory. DefinedNames samples write to main directory, which (a) means they aren't stored with others, and (b) they aren't ignored by git so look like changed files. The tests are also simplified by requiring Header rather than Bootstrap, making use of Helper. * Resolve XSS Vulnerability in the HTML Writer (#1719) Resolve XSS Vulnerability in the HTML Writer * Drop Travis * Automatic GitHub releases from git tags * Improve Coverage in src/PhpSpreadsheet There are no changes to code. Additional tests are added, so that the following 6 items now have 100% test coverage: - Comment - DefinedName - DocumentGenerator - IOFactory - NamedFormula - NamedRange * Changes for Scrutinizer Two changes to fix minor problems reported by Scrutinizer. * Spelling: Tou -> You * Fix for 1735 (Incorrect activeSheetIndex after RemoveSheetByIndex) (#1743) This is a fix for issue #1735. It adds tests for this situation, and similar situations involving adding new sheets and accessing existing ones. Coverage for Spreadsheet.php increases from 69% to 75% as a result. * Update change log * Fix for 3 Issues Involving ReadXlsx and NamedRange (#1742) * Fix for 3 Issues Involving ReadXlsx and NamedRange Issues #1686 and #1723, which provide sample spreadsheets, are probably solved by this ticket. Issue #1730 is also probably solved, but I have no way to verify. There are two problems with how PhpSpreadsheet is handling things now. Although the first problem is much less severe, and isn't really a factor in the issues named above, it is helpful to get it out of the way first. If you define a named range in Excel, and then delete the sheet where the range exists, Excel saves the range as #REF!. If there is a cell which references the range, it will similarly have the value #REF! when you open the Excel file. Currently, PhpSpreadsheet discards the #REF! definition, so a cell which references the range will appear as #NAME? rather than #REF!. This PR changes the behavior so that PhpSpreadsheet retains the #REF! definition, and cells which reference it will appear as #REF!. The second problem is the more severe, and is, I believe, responsible for the 3 issues identified above. If you define a named range and the sheet on which the range is defined does not exist at the time, Excel will save the range as something like: '[1]Unknown Sheet'!$A$1 If a cell references such a range, Excel will again display #REF!. PhpSpreadsheet currently throws an Exception when it encounters such a definition while reading the file. This PR changes the behavior so that PhpSpreadsheet saves the definition as #REF!, and cells which reference it will behave similarly. For the record, I will note that Excel does not magically recalculate when a missing sheet is subsequently added, despite the fact that the reference might now become resolvable. PhpSpreadsheet behaves likewise. * Remove Dead Code in Test Identified it after push but before merge. * Update change log * Apply Column and Row Styles to Existing Cells (#1721) * Apply Column and Row Styles to Existing Cells This is a fix for issue #1712. When a style is applied to an entire row or column, it is currently only effective for cells which don't already contain a value. The code needs to iterate through existing cells in the row/column in order to apply the style to them. This could be considered a breaking change, however, I believe that the change makes things operate as users would expect, and that the existing implementation is incomplete. The change also removes protected element conditionalStyles from the Style class. That element is an unused remnant, and can no longer be set or retrieved - methods getConditionalStyles and setConditionalStyles actually act on an element in the Worksheet class. Finally, additional tests are added so that Style, and in fact the entire Style directory, now has 100% test coverage. * Scrutinizer Changes Scrutinizer flagged 6 statements. 5 can be easily corrected. One is absolutely wrong (it thinks iterating through cells in column can return null). Let's see if we can satisfy it. * Remove Exception For CellIterator on Empty Row/Column For my first attempt at this change, which corrects a bug by updating styles for non-empty cells when a style is set on a row or column, I wished to make things more efficient by using setIterateOnlyExistingCells, something which the existing documentation recommends. This caused an exception to be generated when the row or column is empty. So I removed that part of the change while I researched what was going on. I have completed that research. The existing code does throw an exception when the row/column is empty and iterateOnlyExistingCells is true. However, that does not seem like a reasonable action. This situation is analagous to iterating over an empty array, and that action is legal and does not throw. The same should apply here. There were no tests for this situation, and now there are. I have added additional tests, and coverage for all of RowCellIterator, ColumnCellIterator, and CellIterator are all now 100%. Some of my new tests were added in new members, because the existing tests all relied on mocking, which was not the best choice for the new tests. One of the existing tests for RowCellIteratorTest (testSeekOutOfRange) was wrong; it issued the expected exception, but for the wrong reason. I have added an additional test to ensure that it fails "correctly". The existing documentation says that the default value for IterateOnlyExistingCells is true. In fact, the default value is false. I have corrected the documentation. * More Scrutinizer I believe its analysis is incorrect, but this should silence it. * DocBlock Correction ColumnCellIterator DocBlock for current indicated it could return null or Cell, but it can really return only Cell. This had caused Scrutinizer to complain earlier. * PHP8 Environment Appears to be Fixed Cosmetic change to Doc member. I suspect there is a way to rerun all the tests without another push, but I have been unable to figure out how. * Update change log * TextData Coverage and Minor Bug Fixes (#1744) This had been intended to get 100% coverage for TextData functions, and it does that. However, some minor bugs requiring source changes arose during testing. - the Excel CHAR function restricts its argument to 1-255. PhpSpreadsheet CHARACTER had been allowing 0+. Also, there is no need to test if iconv exists, since it is part of Composer requirements. - The DOLLAR function had been returning NUM for invalid arguments. Excel returns VALUE. Also, negative amounts were not being handled correctly. - The FIXEDFORMAT function had been returning NUM for invalid arguments. Excel FIXED returns VALUE. * Replace anti-xss with html purifier (#1751) * Replace voku/anti-xss with ezyang/htmlpurifier. Despite anti-xss being a smaller footprint dependency, an a better license fit with our MIT license, there are issues with it's automatic it sanitisation of global variables causing side effects * Additional unit tests for xss in html writer cell comments * Fix bug #1626 where values of 0 were "rounded" up/down as if they were not 0 (#1627) * Fix bug where values of 0 were "rounded" up/down as if they were not 0 * Update change log * Fix for #1612 - SLK Long File Name (#1706) Issue has been marked stale, but ... Sylk read sets worksheet title to filename (minus .slk). If that is >31 characters, PhpSpreadsheet throws Exception. This change truncates sheet title, as Excel does, to 31 characters. * Update change log * worksheet: fix if cellValue does not exist (#1727) The condition is FALSE if the cell does not exist in the flipped table, but anyway, it is sent in to a method requiring 'string' type, causing it to fail. * fixes #1655 issue (#1656) Resolve problem with incorrectly defined hyperlinks * Add 'ps' suffix to printer settings resources IDs (#1690) * Add 'ps' suffix to printer settings resources IDs * Update change log * Fix pixelsToPoints conversion (for HTML col width) (#1733) * DocBlock Change in Styles/Conditional (#1697) Scrutinizer reported a minor error in a test involving a module which I was not changing. Styles/Conditional function setConditions can take a scalar or an array as a parameter, but DocBlock says it only expects array. I did not wish to add the extra module to my PR, but made a note to self to fix that after PR was installed. That has now happened, and it makes for a good case for me to see all the PHP8/Composer2/etc. changes that have happened recently. * Merge pull request #1698 * Merge pull request #4 from PHPOffice/master * Restore Omitted Read XML Test * Fix for bug #1592 (UPDATED) (#1623) * Fix for Xls when BIFF8 SST (FCh) has bad Shared string length * Update change log * Add nightly PHP 8.1 dev to github actions (#1763) * Fix compatibility with ext-gd on php 8 (#1762) * CSV - Guess Encoding, Handle Null-string Escape (#1717) * CSV - Guess Encoding, Handle Null-string Escape This is in response to issue #1647 (detect CSV character encoding). First, my tests with mb_detect_encoding indicate that it doesn't work well enough; regardless, users can always do that on their own if they deem it useful. Rolling my own is also troublesome, but I can at least: a. Check for BOM (UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE). b. Do some heuristic tests for each of the above encodings. c. Fallback to a user-specified encoding (default CP1252) if a and b don't yield result. I think this is probably useful enough to include, and relatively easy to expand if other potential encodings should be considered. Starting with PHP7.4, fgetcsv allows specification of null string as escape character in fgetcsv. This is a much better choice than the PHP (and PhpSpreadsheet) default of backslash in that it handles the file in the same manner as Excel does. There is one statement in Reader/CSV which would be adversely affected if the caller so specified (building a regular expression under the assumption that escape character is a single character). Fix that statement appropriately and add tests. * Update changelog * Update Units of Measure supported by the CONVERT() function (#1768) Now supports all current UoM in all categories, with both 1- and 2-character multiplier prefixes, and binary multiplier prefixes, including the new Temperature scales * Changelog for 1.16.0 release * Fix date tests withut specified year for current year 2021 (#1774) * Mrand of zero to any multiple should return 0 (#1773) * WIP Inherited Scrutinizer Recommendations - 1 of 3 I tried to sync my fork with the main project, as I have done several times before. However, the GitHub interface to do this had changed, and it appears that I did not make the optimal selection when I had a choice. Consequently, all the merges that happened to base between the last time I synchronized and this time appear to be part of any PR that I push. "Files changed" remains correct for my new PRs, but there appear to be many more commits involved than is actually the case. I will, at some point, delete and re-create my fork, and pay much closer attention in future when I want to sync my fork with the main project. Because of this set-up, Scrutinizer reports flaws in code that I haven't actually changed in my PRs #1799 and #1800. It still passes them, but, as long as I'm aware of the problems, I may as well attempt to correct them. The following are not part of those PRs: - 5 problems spread over 4 different members - 12 problems in Calculation/Engineering - 15 problems in Reader/XML I shall attempt to resolve these via 3 separate PRs, of which this is the first. * Try Hyperlink Again Scrutinizer still didn't like it as fixed. * Another Crack at Hyperlink This should work. Co-authored-by: Mark Baker Co-authored-by: Adrien Crivelli Co-authored-by: Ryan McAllen Co-authored-by: Flinsch <220455+Flinsch@users.noreply.github.com> Co-authored-by: Jan Sverre Riksfjord Co-authored-by: Max Kalyabin Co-authored-by: Sébastien Despont Co-authored-by: Guilliam Xavier Co-authored-by: Gianluca Giovinazzo Co-authored-by: Alexander M. Turek Co-authored-by: Martins Sipenko --- src/PhpSpreadsheet/Reader/Csv.php | 5 +++-- src/PhpSpreadsheet/Reader/Xlsx.php | 3 +-- src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php | 4 +++- src/PhpSpreadsheet/Spreadsheet.php | 4 +++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Csv.php b/src/PhpSpreadsheet/Reader/Csv.php index 1495d102..92b0f6ac 100644 --- a/src/PhpSpreadsheet/Reader/Csv.php +++ b/src/PhpSpreadsheet/Reader/Csv.php @@ -334,7 +334,7 @@ class Csv extends BaseReader public function loadIntoExisting($pFilename, Spreadsheet $spreadsheet) { $lineEnding = ini_get('auto_detect_line_endings'); - ini_set('auto_detect_line_endings', true); + ini_set('auto_detect_line_endings', '1'); // Open file $this->openFileOrMemory($pFilename); @@ -528,7 +528,8 @@ class Csv extends BaseReader fclose($this->fileHandle); // Trust file extension if any - $extension = strtolower(pathinfo($pFilename, PATHINFO_EXTENSION)); + $extension = pathinfo($pFilename, PATHINFO_EXTENSION); + $extension = is_array($extension) ? '' : strtolower($extension); if (in_array($extension, ['csv', 'tsv'])) { return true; } diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index eafa36b5..c05f77de 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -186,8 +186,7 @@ class Xlsx extends BaseReader ); if ($xmlWorkbook->sheets) { $dir = dirname($rel['Target']); - /** @var SimpleXMLElement $eleSheet */ - foreach ($xmlWorkbook->sheets->sheet as $eleSheet) { + foreach ($xmlWorkbook->sheets->sheet->children() as $eleSheet) { $tmpInfo = [ 'worksheetName' => (string) $eleSheet['name'], 'lastColumnLetter' => 'A', diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php b/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php index 106fd44e..a9afce38 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php @@ -29,7 +29,9 @@ class Hyperlinks public function setHyperlinks(SimpleXMLElement $worksheetXml): void { foreach ($worksheetXml->hyperlink as $hyperlink) { - $this->setHyperlink($hyperlink, $this->worksheet); + if ($hyperlink !== null) { + $this->setHyperlink($hyperlink, $this->worksheet); + } } } diff --git a/src/PhpSpreadsheet/Spreadsheet.php b/src/PhpSpreadsheet/Spreadsheet.php index c8e8f72c..51f558a1 100644 --- a/src/PhpSpreadsheet/Spreadsheet.php +++ b/src/PhpSpreadsheet/Spreadsheet.php @@ -373,7 +373,9 @@ class Spreadsheet */ private function getExtensionOnly($path) { - return pathinfo($path, PATHINFO_EXTENSION); + $extension = pathinfo($path, PATHINFO_EXTENSION); + + return is_array($extension) ? '' : $extension; } /** From 70c3803c4652575cf644440329718873285a23ec Mon Sep 17 00:00:00 2001 From: oleibman Date: Sun, 31 Jan 2021 08:12:53 -0800 Subject: [PATCH 028/187] Inherited Scrutinizer Recommendations - 2 of 3 (#1807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make DefinedNames Samples Consistent With Other Samples (#1707) All other Samples write to temporary directory. DefinedNames samples write to main directory, which (a) means they aren't stored with others, and (b) they aren't ignored by git so look like changed files. The tests are also simplified by requiring Header rather than Bootstrap, making use of Helper. * Resolve XSS Vulnerability in the HTML Writer (#1719) Resolve XSS Vulnerability in the HTML Writer * Drop Travis * Automatic GitHub releases from git tags * Improve Coverage in src/PhpSpreadsheet There are no changes to code. Additional tests are added, so that the following 6 items now have 100% test coverage: - Comment - DefinedName - DocumentGenerator - IOFactory - NamedFormula - NamedRange * Changes for Scrutinizer Two changes to fix minor problems reported by Scrutinizer. * Spelling: Tou -> You * Fix for 1735 (Incorrect activeSheetIndex after RemoveSheetByIndex) (#1743) This is a fix for issue #1735. It adds tests for this situation, and similar situations involving adding new sheets and accessing existing ones. Coverage for Spreadsheet.php increases from 69% to 75% as a result. * Update change log * Fix for 3 Issues Involving ReadXlsx and NamedRange (#1742) * Fix for 3 Issues Involving ReadXlsx and NamedRange Issues #1686 and #1723, which provide sample spreadsheets, are probably solved by this ticket. Issue #1730 is also probably solved, but I have no way to verify. There are two problems with how PhpSpreadsheet is handling things now. Although the first problem is much less severe, and isn't really a factor in the issues named above, it is helpful to get it out of the way first. If you define a named range in Excel, and then delete the sheet where the range exists, Excel saves the range as #REF!. If there is a cell which references the range, it will similarly have the value #REF! when you open the Excel file. Currently, PhpSpreadsheet discards the #REF! definition, so a cell which references the range will appear as #NAME? rather than #REF!. This PR changes the behavior so that PhpSpreadsheet retains the #REF! definition, and cells which reference it will appear as #REF!. The second problem is the more severe, and is, I believe, responsible for the 3 issues identified above. If you define a named range and the sheet on which the range is defined does not exist at the time, Excel will save the range as something like: '[1]Unknown Sheet'!$A$1 If a cell references such a range, Excel will again display #REF!. PhpSpreadsheet currently throws an Exception when it encounters such a definition while reading the file. This PR changes the behavior so that PhpSpreadsheet saves the definition as #REF!, and cells which reference it will behave similarly. For the record, I will note that Excel does not magically recalculate when a missing sheet is subsequently added, despite the fact that the reference might now become resolvable. PhpSpreadsheet behaves likewise. * Remove Dead Code in Test Identified it after push but before merge. * Update change log * Apply Column and Row Styles to Existing Cells (#1721) * Apply Column and Row Styles to Existing Cells This is a fix for issue #1712. When a style is applied to an entire row or column, it is currently only effective for cells which don't already contain a value. The code needs to iterate through existing cells in the row/column in order to apply the style to them. This could be considered a breaking change, however, I believe that the change makes things operate as users would expect, and that the existing implementation is incomplete. The change also removes protected element conditionalStyles from the Style class. That element is an unused remnant, and can no longer be set or retrieved - methods getConditionalStyles and setConditionalStyles actually act on an element in the Worksheet class. Finally, additional tests are added so that Style, and in fact the entire Style directory, now has 100% test coverage. * Scrutinizer Changes Scrutinizer flagged 6 statements. 5 can be easily corrected. One is absolutely wrong (it thinks iterating through cells in column can return null). Let's see if we can satisfy it. * Remove Exception For CellIterator on Empty Row/Column For my first attempt at this change, which corrects a bug by updating styles for non-empty cells when a style is set on a row or column, I wished to make things more efficient by using setIterateOnlyExistingCells, something which the existing documentation recommends. This caused an exception to be generated when the row or column is empty. So I removed that part of the change while I researched what was going on. I have completed that research. The existing code does throw an exception when the row/column is empty and iterateOnlyExistingCells is true. However, that does not seem like a reasonable action. This situation is analagous to iterating over an empty array, and that action is legal and does not throw. The same should apply here. There were no tests for this situation, and now there are. I have added additional tests, and coverage for all of RowCellIterator, ColumnCellIterator, and CellIterator are all now 100%. Some of my new tests were added in new members, because the existing tests all relied on mocking, which was not the best choice for the new tests. One of the existing tests for RowCellIteratorTest (testSeekOutOfRange) was wrong; it issued the expected exception, but for the wrong reason. I have added an additional test to ensure that it fails "correctly". The existing documentation says that the default value for IterateOnlyExistingCells is true. In fact, the default value is false. I have corrected the documentation. * More Scrutinizer I believe its analysis is incorrect, but this should silence it. * DocBlock Correction ColumnCellIterator DocBlock for current indicated it could return null or Cell, but it can really return only Cell. This had caused Scrutinizer to complain earlier. * PHP8 Environment Appears to be Fixed Cosmetic change to Doc member. I suspect there is a way to rerun all the tests without another push, but I have been unable to figure out how. * Update change log * TextData Coverage and Minor Bug Fixes (#1744) This had been intended to get 100% coverage for TextData functions, and it does that. However, some minor bugs requiring source changes arose during testing. - the Excel CHAR function restricts its argument to 1-255. PhpSpreadsheet CHARACTER had been allowing 0+. Also, there is no need to test if iconv exists, since it is part of Composer requirements. - The DOLLAR function had been returning NUM for invalid arguments. Excel returns VALUE. Also, negative amounts were not being handled correctly. - The FIXEDFORMAT function had been returning NUM for invalid arguments. Excel FIXED returns VALUE. * Replace anti-xss with html purifier (#1751) * Replace voku/anti-xss with ezyang/htmlpurifier. Despite anti-xss being a smaller footprint dependency, an a better license fit with our MIT license, there are issues with it's automatic it sanitisation of global variables causing side effects * Additional unit tests for xss in html writer cell comments * Fix bug #1626 where values of 0 were "rounded" up/down as if they were not 0 (#1627) * Fix bug where values of 0 were "rounded" up/down as if they were not 0 * Update change log * Fix for #1612 - SLK Long File Name (#1706) Issue has been marked stale, but ... Sylk read sets worksheet title to filename (minus .slk). If that is >31 characters, PhpSpreadsheet throws Exception. This change truncates sheet title, as Excel does, to 31 characters. * Update change log * worksheet: fix if cellValue does not exist (#1727) The condition is FALSE if the cell does not exist in the flipped table, but anyway, it is sent in to a method requiring 'string' type, causing it to fail. * fixes #1655 issue (#1656) Resolve problem with incorrectly defined hyperlinks * Add 'ps' suffix to printer settings resources IDs (#1690) * Add 'ps' suffix to printer settings resources IDs * Update change log * Fix pixelsToPoints conversion (for HTML col width) (#1733) * DocBlock Change in Styles/Conditional (#1697) Scrutinizer reported a minor error in a test involving a module which I was not changing. Styles/Conditional function setConditions can take a scalar or an array as a parameter, but DocBlock says it only expects array. I did not wish to add the extra module to my PR, but made a note to self to fix that after PR was installed. That has now happened, and it makes for a good case for me to see all the PHP8/Composer2/etc. changes that have happened recently. * Merge pull request #1698 * Merge pull request #4 from PHPOffice/master * Restore Omitted Read XML Test * Fix for bug #1592 (UPDATED) (#1623) * Fix for Xls when BIFF8 SST (FCh) has bad Shared string length * Update change log * Add nightly PHP 8.1 dev to github actions (#1763) * Fix compatibility with ext-gd on php 8 (#1762) * CSV - Guess Encoding, Handle Null-string Escape (#1717) * CSV - Guess Encoding, Handle Null-string Escape This is in response to issue #1647 (detect CSV character encoding). First, my tests with mb_detect_encoding indicate that it doesn't work well enough; regardless, users can always do that on their own if they deem it useful. Rolling my own is also troublesome, but I can at least: a. Check for BOM (UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE). b. Do some heuristic tests for each of the above encodings. c. Fallback to a user-specified encoding (default CP1252) if a and b don't yield result. I think this is probably useful enough to include, and relatively easy to expand if other potential encodings should be considered. Starting with PHP7.4, fgetcsv allows specification of null string as escape character in fgetcsv. This is a much better choice than the PHP (and PhpSpreadsheet) default of backslash in that it handles the file in the same manner as Excel does. There is one statement in Reader/CSV which would be adversely affected if the caller so specified (building a regular expression under the assumption that escape character is a single character). Fix that statement appropriately and add tests. * Update changelog * Update Units of Measure supported by the CONVERT() function (#1768) Now supports all current UoM in all categories, with both 1- and 2-character multiplier prefixes, and binary multiplier prefixes, including the new Temperature scales * Changelog for 1.16.0 release * Fix date tests withut specified year for current year 2021 (#1774) * Mrand of zero to any multiple should return 0 (#1773) * Inherited Scrutinizer Recommendations - 2 of 3 I tried to sync my fork with the main project, as I have done several times before. However, the GitHub interface to do this had changed, and it appears that I did not make the optimal selection when I had a choice. Consequently, all the merges that happened to base between the last time I synchronized and this time appear to be part of any PR that I push. "Files changed" remains correct for my new PRs, but there appear to be many more commits involved than is actually the case. I will, at some point, delete and re-create my fork, and pay much closer attention in future when I want to sync my fork with the main project. Because of this set-up, Scrutinizer reports flaws in code that I haven't actually changed in my PRs #1799 and #1800. It still passes them, but, as long as I'm aware of the problems, I may as well attempt to correct them. The following are not part of those PRs: - 5 problems spread over 4 different members - 12 problems in Calculation/Engineering - 15 problems in Reader/XML I shall attempt to resolve these via 3 separate PRs, of which this is the second. * Fixed Most of the Problems, But Some New Ones Cropped Up Trying once more to satisfy Scrutinizer. Co-authored-by: Mark Baker Co-authored-by: Adrien Crivelli Co-authored-by: Ryan McAllen Co-authored-by: Flinsch <220455+Flinsch@users.noreply.github.com> Co-authored-by: Jan Sverre Riksfjord Co-authored-by: Max Kalyabin Co-authored-by: Sébastien Despont Co-authored-by: Guilliam Xavier Co-authored-by: Gianluca Giovinazzo Co-authored-by: Alexander M. Turek Co-authored-by: Martins Sipenko --- .../Calculation/Engineering.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 57116f28..319a2ed6 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -377,7 +377,7 @@ class Engineering } } if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $x = floor($x); + $x = floor((float) $x); } $x = (string) $x; if (strlen($x) > preg_match_all('/[01]/', $x, $out)) { @@ -432,7 +432,7 @@ class Engineering } } if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $x = floor($x); + $x = floor((float) $x); } $x = (string) $x; if (strlen($x) > preg_match_all('/[01]/', $x, $out)) { @@ -442,9 +442,9 @@ class Engineering return Functions::NAN(); } elseif (strlen($x) == 10) { // Two's Complement - return str_repeat('F', 8) . substr(strtoupper(dechex(bindec(substr($x, -9)))), -2); + return str_repeat('F', 8) . substr(strtoupper(dechex((int) bindec(substr($x, -9)))), -2); } - $hexVal = (string) strtoupper(dechex(bindec($x))); + $hexVal = (string) strtoupper(dechex((int) bindec($x))); return self::nbrConversionFormat($hexVal, $places); } @@ -485,7 +485,7 @@ class Engineering } } if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $x = floor($x); + $x = floor((float) $x); } $x = (string) $x; if (strlen($x) > preg_match_all('/[01]/', $x, $out)) { @@ -495,9 +495,9 @@ class Engineering return Functions::NAN(); } elseif (strlen($x) == 10) { // Two's Complement - return str_repeat('7', 7) . substr(strtoupper(decoct(bindec(substr($x, -9)))), -3); + return str_repeat('7', 7) . substr(strtoupper(decoct((int) bindec(substr($x, -9)))), -3); } - $octVal = (string) decoct(bindec($x)); + $octVal = (string) decoct((int) bindec($x)); return self::nbrConversionFormat($octVal, $places); } @@ -546,7 +546,7 @@ class Engineering return Functions::VALUE(); } - $x = (string) floor($x); + $x = (int) floor((float) $x); if ($x < -512 || $x > 511) { return Functions::NAN(); } @@ -604,7 +604,7 @@ class Engineering if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) { return Functions::VALUE(); } - $x = (string) floor($x); + $x = (int) floor((float) $x); $r = strtoupper(dechex($x)); if (strlen($r) == 8) { // Two's Complement @@ -658,7 +658,7 @@ class Engineering if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) { return Functions::VALUE(); } - $x = (string) floor($x); + $x = (int) floor((float) $x); $r = decoct($x); if (strlen($r) == 11) { // Two's Complement @@ -945,7 +945,7 @@ class Engineering if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) { return Functions::NAN(); } - $hexVal = strtoupper(dechex(self::OCTTODEC($x))); + $hexVal = strtoupper(dechex((int) self::OCTTODEC((int) $x))); return self::nbrConversionFormat($hexVal, $places); } From 308bc64d91faadf01442001d0cfbea4787e089e3 Mon Sep 17 00:00:00 2001 From: oleibman Date: Sun, 31 Jan 2021 08:13:14 -0800 Subject: [PATCH 029/187] Inherited Scrutinizer Recommendations - 3 of 3 (#1808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make DefinedNames Samples Consistent With Other Samples (#1707) All other Samples write to temporary directory. DefinedNames samples write to main directory, which (a) means they aren't stored with others, and (b) they aren't ignored by git so look like changed files. The tests are also simplified by requiring Header rather than Bootstrap, making use of Helper. * Resolve XSS Vulnerability in the HTML Writer (#1719) Resolve XSS Vulnerability in the HTML Writer * Drop Travis * Automatic GitHub releases from git tags * Improve Coverage in src/PhpSpreadsheet There are no changes to code. Additional tests are added, so that the following 6 items now have 100% test coverage: - Comment - DefinedName - DocumentGenerator - IOFactory - NamedFormula - NamedRange * Changes for Scrutinizer Two changes to fix minor problems reported by Scrutinizer. * Spelling: Tou -> You * Fix for 1735 (Incorrect activeSheetIndex after RemoveSheetByIndex) (#1743) This is a fix for issue #1735. It adds tests for this situation, and similar situations involving adding new sheets and accessing existing ones. Coverage for Spreadsheet.php increases from 69% to 75% as a result. * Update change log * Fix for 3 Issues Involving ReadXlsx and NamedRange (#1742) * Fix for 3 Issues Involving ReadXlsx and NamedRange Issues #1686 and #1723, which provide sample spreadsheets, are probably solved by this ticket. Issue #1730 is also probably solved, but I have no way to verify. There are two problems with how PhpSpreadsheet is handling things now. Although the first problem is much less severe, and isn't really a factor in the issues named above, it is helpful to get it out of the way first. If you define a named range in Excel, and then delete the sheet where the range exists, Excel saves the range as #REF!. If there is a cell which references the range, it will similarly have the value #REF! when you open the Excel file. Currently, PhpSpreadsheet discards the #REF! definition, so a cell which references the range will appear as #NAME? rather than #REF!. This PR changes the behavior so that PhpSpreadsheet retains the #REF! definition, and cells which reference it will appear as #REF!. The second problem is the more severe, and is, I believe, responsible for the 3 issues identified above. If you define a named range and the sheet on which the range is defined does not exist at the time, Excel will save the range as something like: '[1]Unknown Sheet'!$A$1 If a cell references such a range, Excel will again display #REF!. PhpSpreadsheet currently throws an Exception when it encounters such a definition while reading the file. This PR changes the behavior so that PhpSpreadsheet saves the definition as #REF!, and cells which reference it will behave similarly. For the record, I will note that Excel does not magically recalculate when a missing sheet is subsequently added, despite the fact that the reference might now become resolvable. PhpSpreadsheet behaves likewise. * Remove Dead Code in Test Identified it after push but before merge. * Update change log * Apply Column and Row Styles to Existing Cells (#1721) * Apply Column and Row Styles to Existing Cells This is a fix for issue #1712. When a style is applied to an entire row or column, it is currently only effective for cells which don't already contain a value. The code needs to iterate through existing cells in the row/column in order to apply the style to them. This could be considered a breaking change, however, I believe that the change makes things operate as users would expect, and that the existing implementation is incomplete. The change also removes protected element conditionalStyles from the Style class. That element is an unused remnant, and can no longer be set or retrieved - methods getConditionalStyles and setConditionalStyles actually act on an element in the Worksheet class. Finally, additional tests are added so that Style, and in fact the entire Style directory, now has 100% test coverage. * Scrutinizer Changes Scrutinizer flagged 6 statements. 5 can be easily corrected. One is absolutely wrong (it thinks iterating through cells in column can return null). Let's see if we can satisfy it. * Remove Exception For CellIterator on Empty Row/Column For my first attempt at this change, which corrects a bug by updating styles for non-empty cells when a style is set on a row or column, I wished to make things more efficient by using setIterateOnlyExistingCells, something which the existing documentation recommends. This caused an exception to be generated when the row or column is empty. So I removed that part of the change while I researched what was going on. I have completed that research. The existing code does throw an exception when the row/column is empty and iterateOnlyExistingCells is true. However, that does not seem like a reasonable action. This situation is analagous to iterating over an empty array, and that action is legal and does not throw. The same should apply here. There were no tests for this situation, and now there are. I have added additional tests, and coverage for all of RowCellIterator, ColumnCellIterator, and CellIterator are all now 100%. Some of my new tests were added in new members, because the existing tests all relied on mocking, which was not the best choice for the new tests. One of the existing tests for RowCellIteratorTest (testSeekOutOfRange) was wrong; it issued the expected exception, but for the wrong reason. I have added an additional test to ensure that it fails "correctly". The existing documentation says that the default value for IterateOnlyExistingCells is true. In fact, the default value is false. I have corrected the documentation. * More Scrutinizer I believe its analysis is incorrect, but this should silence it. * DocBlock Correction ColumnCellIterator DocBlock for current indicated it could return null or Cell, but it can really return only Cell. This had caused Scrutinizer to complain earlier. * PHP8 Environment Appears to be Fixed Cosmetic change to Doc member. I suspect there is a way to rerun all the tests without another push, but I have been unable to figure out how. * Update change log * TextData Coverage and Minor Bug Fixes (#1744) This had been intended to get 100% coverage for TextData functions, and it does that. However, some minor bugs requiring source changes arose during testing. - the Excel CHAR function restricts its argument to 1-255. PhpSpreadsheet CHARACTER had been allowing 0+. Also, there is no need to test if iconv exists, since it is part of Composer requirements. - The DOLLAR function had been returning NUM for invalid arguments. Excel returns VALUE. Also, negative amounts were not being handled correctly. - The FIXEDFORMAT function had been returning NUM for invalid arguments. Excel FIXED returns VALUE. * Replace anti-xss with html purifier (#1751) * Replace voku/anti-xss with ezyang/htmlpurifier. Despite anti-xss being a smaller footprint dependency, an a better license fit with our MIT license, there are issues with it's automatic it sanitisation of global variables causing side effects * Additional unit tests for xss in html writer cell comments * Fix bug #1626 where values of 0 were "rounded" up/down as if they were not 0 (#1627) * Fix bug where values of 0 were "rounded" up/down as if they were not 0 * Update change log * Fix for #1612 - SLK Long File Name (#1706) Issue has been marked stale, but ... Sylk read sets worksheet title to filename (minus .slk). If that is >31 characters, PhpSpreadsheet throws Exception. This change truncates sheet title, as Excel does, to 31 characters. * Update change log * worksheet: fix if cellValue does not exist (#1727) The condition is FALSE if the cell does not exist in the flipped table, but anyway, it is sent in to a method requiring 'string' type, causing it to fail. * fixes #1655 issue (#1656) Resolve problem with incorrectly defined hyperlinks * Add 'ps' suffix to printer settings resources IDs (#1690) * Add 'ps' suffix to printer settings resources IDs * Update change log * Fix pixelsToPoints conversion (for HTML col width) (#1733) * DocBlock Change in Styles/Conditional (#1697) Scrutinizer reported a minor error in a test involving a module which I was not changing. Styles/Conditional function setConditions can take a scalar or an array as a parameter, but DocBlock says it only expects array. I did not wish to add the extra module to my PR, but made a note to self to fix that after PR was installed. That has now happened, and it makes for a good case for me to see all the PHP8/Composer2/etc. changes that have happened recently. * Merge pull request #1698 * Merge pull request #4 from PHPOffice/master * Restore Omitted Read XML Test * Fix for bug #1592 (UPDATED) (#1623) * Fix for Xls when BIFF8 SST (FCh) has bad Shared string length * Update change log * Add nightly PHP 8.1 dev to github actions (#1763) * Fix compatibility with ext-gd on php 8 (#1762) * CSV - Guess Encoding, Handle Null-string Escape (#1717) * CSV - Guess Encoding, Handle Null-string Escape This is in response to issue #1647 (detect CSV character encoding). First, my tests with mb_detect_encoding indicate that it doesn't work well enough; regardless, users can always do that on their own if they deem it useful. Rolling my own is also troublesome, but I can at least: a. Check for BOM (UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE). b. Do some heuristic tests for each of the above encodings. c. Fallback to a user-specified encoding (default CP1252) if a and b don't yield result. I think this is probably useful enough to include, and relatively easy to expand if other potential encodings should be considered. Starting with PHP7.4, fgetcsv allows specification of null string as escape character in fgetcsv. This is a much better choice than the PHP (and PhpSpreadsheet) default of backslash in that it handles the file in the same manner as Excel does. There is one statement in Reader/CSV which would be adversely affected if the caller so specified (building a regular expression under the assumption that escape character is a single character). Fix that statement appropriately and add tests. * Update changelog * Update Units of Measure supported by the CONVERT() function (#1768) Now supports all current UoM in all categories, with both 1- and 2-character multiplier prefixes, and binary multiplier prefixes, including the new Temperature scales * Changelog for 1.16.0 release * Fix date tests withut specified year for current year 2021 (#1774) * Mrand of zero to any multiple should return 0 (#1773) * Inherited Scrutinizer Recommendations - 3 of 3 I tried to sync my fork with the main project, as I have done several times before. However, the GitHub interface to do this had changed, and it appears that I did not make the optimal selection when I had a choice. Consequently, all the merges that happened to base between the last time I synchronized and this time appear to be part of any PR that I push. "Files changed" remains correct for my new PRs, but there appear to be many more commits involved than is actually the case. I will, at some point, delete and re-create my fork, and pay much closer attention in future when I want to sync my fork with the main project. Because of this set-up, Scrutinizer reports flaws in code that I haven't actually changed in my PRs #1799 and #1800. It still passes them, but, as long as I'm aware of the problems, I may as well attempt to correct them. The following are not part of those PRs: - 5 problems spread over 4 different members - 12 problems in Calculation/Engineering - 15 problems in Reader/XML I shall attempt to resolve these via 3 separate PRs, of which this is the third. * The Usual Fixed some Scrutinizer problems, some new ones popped up. * More Scrutinizer I think it's wrong in a lot of these cases. Although I am working around all of them, I intend to file a bug report with them. Co-authored-by: Mark Baker Co-authored-by: Adrien Crivelli Co-authored-by: Ryan McAllen Co-authored-by: Flinsch <220455+Flinsch@users.noreply.github.com> Co-authored-by: Jan Sverre Riksfjord Co-authored-by: Max Kalyabin Co-authored-by: Sébastien Despont Co-authored-by: Guilliam Xavier Co-authored-by: Gianluca Giovinazzo Co-authored-by: Alexander M. Turek Co-authored-by: Martins Sipenko --- src/PhpSpreadsheet/Reader/Xml.php | 51 ++++++++++++++++++------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index 11aa1df3..9de88233 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -191,7 +191,7 @@ class Xml extends BaseReader $xml_ss = $xml->children($namespaces['ss']); foreach ($xml_ss->Worksheet as $worksheet) { - $worksheet_ss = $worksheet->attributes($namespaces['ss']); + $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); $worksheetNames[] = (string) $worksheet_ss['Name']; } @@ -221,7 +221,7 @@ class Xml extends BaseReader $worksheetID = 1; $xml_ss = $xml->children($namespaces['ss']); foreach ($xml_ss->Worksheet as $worksheet) { - $worksheet_ss = $worksheet->attributes($namespaces['ss']); + $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); $tmpInfo = []; $tmpInfo['worksheetName'] = ''; @@ -381,13 +381,13 @@ class Xml extends BaseReader } if (isset($xml->CustomDocumentProperties)) { foreach ($xml->CustomDocumentProperties[0] as $propertyName => $propertyValue) { - $propertyAttributes = $propertyValue->attributes($namespaces['dt']); + $propertyAttributes = self::getAttributes($propertyValue, $namespaces['dt']); $propertyName = preg_replace_callback('/_x([0-9a-f]{4})_/i', ['self', 'hex2str'], $propertyName); $propertyType = Properties::PROPERTY_TYPE_UNKNOWN; switch ((string) $propertyAttributes) { case 'string': $propertyType = Properties::PROPERTY_TYPE_STRING; - $propertyValue = trim($propertyValue); + $propertyValue = trim((string) $propertyValue); break; case 'boolean': @@ -407,7 +407,7 @@ class Xml extends BaseReader break; case 'dateTime.tz': $propertyType = Properties::PROPERTY_TYPE_DATE; - $propertyValue = strtotime(trim($propertyValue)); + $propertyValue = strtotime(trim((string) $propertyValue)); break; } @@ -420,8 +420,9 @@ class Xml extends BaseReader $worksheetID = 0; $xml_ss = $xml->children($namespaces['ss']); - foreach ($xml_ss->Worksheet as $worksheet) { - $worksheet_ss = $worksheet->attributes($namespaces['ss']); + foreach ($xml_ss->Worksheet as $worksheetx) { + $worksheet = ($worksheetx === null) ? new SimpleXMLElement('') : $worksheetx; + $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); if ( (isset($this->loadSheetsOnly)) && (isset($worksheet_ss['Name'])) && @@ -444,7 +445,7 @@ class Xml extends BaseReader // locally scoped defined names if (isset($worksheet->Names[0])) { foreach ($worksheet->Names[0] as $definedName) { - $definedName_ss = $definedName->attributes($namespaces['ss']); + $definedName_ss = self::getAttributes($definedName, $namespaces['ss']); $name = (string) $definedName_ss['Name']; $definedValue = (string) $definedName_ss['RefersTo']; $convertedValue = AddressHelper::convertFormulaToA1($definedValue); @@ -458,7 +459,7 @@ class Xml extends BaseReader $columnID = 'A'; if (isset($worksheet->Table->Column)) { foreach ($worksheet->Table->Column as $columnData) { - $columnData_ss = $columnData->attributes($namespaces['ss']); + $columnData_ss = self::getAttributes($columnData, $namespaces['ss']); if (isset($columnData_ss['Index'])) { $columnID = Coordinate::stringFromColumnIndex((int) $columnData_ss['Index']); } @@ -475,14 +476,14 @@ class Xml extends BaseReader $additionalMergedCells = 0; foreach ($worksheet->Table->Row as $rowData) { $rowHasData = false; - $row_ss = $rowData->attributes($namespaces['ss']); + $row_ss = self::getAttributes($rowData, $namespaces['ss']); if (isset($row_ss['Index'])) { $rowID = (int) $row_ss['Index']; } $columnID = 'A'; foreach ($rowData->Cell as $cell) { - $cell_ss = $cell->attributes($namespaces['ss']); + $cell_ss = self::getAttributes($cell, $namespaces['ss']); if (isset($cell_ss['Index'])) { $columnID = Coordinate::stringFromColumnIndex((int) $cell_ss['Index']); } @@ -524,7 +525,7 @@ class Xml extends BaseReader $cellData = $cell->Data; $cellValue = (string) $cellData; $type = DataType::TYPE_NULL; - $cellData_ss = $cellData->attributes($namespaces['ss']); + $cellData_ss = self::getAttributes($cellData, $namespaces['ss']); if (isset($cellData_ss['Type'])) { $cellDataType = $cellData_ss['Type']; switch ($cellDataType) { @@ -587,7 +588,7 @@ class Xml extends BaseReader $author = (string) $commentAttributes->Author; } $node = $cell->Comment->Data->asXML(); - $annotation = strip_tags($node); + $annotation = strip_tags((string) $node); $spreadsheet->getActiveSheet()->getComment($columnID . $rowID)->setAuthor($author)->setText($this->parseRichText($annotation)); } @@ -610,7 +611,7 @@ class Xml extends BaseReader if ($rowHasData) { if (isset($row_ss['Height'])) { $rowHeight = $row_ss['Height']; - $spreadsheet->getActiveSheet()->getRowDimension($rowID)->setRowHeight($rowHeight); + $spreadsheet->getActiveSheet()->getRowDimension($rowID)->setRowHeight((float) $rowHeight); } } @@ -631,7 +632,7 @@ class Xml extends BaseReader $activeWorksheet = $spreadsheet->setActiveSheetIndex(0); if (isset($xml->Names[0])) { foreach ($xml->Names[0] as $definedName) { - $definedName_ss = $definedName->attributes($namespaces['ss']); + $definedName_ss = self::getAttributes($definedName, $namespaces['ss']); $name = (string) $definedName_ss['Name']; $definedValue = (string) $definedName_ss['RefersTo']; $convertedValue = AddressHelper::convertFormulaToA1($definedValue); @@ -662,10 +663,11 @@ class Xml extends BaseReader } foreach ($xml->Styles[0] as $style) { - $style_ss = $style->attributes($namespaces['ss']); + $style_ss = self::getAttributes($style, $namespaces['ss']); $styleID = (string) $style_ss['ID']; $this->styles[$styleID] = (isset($this->styles['Default'])) ? $this->styles['Default'] : []; - foreach ($style as $styleType => $styleData) { + foreach ($style as $styleType => $styleDatax) { + $styleData = $styleDatax ?? new SimpleXMLElement(''); $styleAttributes = $styleData->attributes($namespaces['ss']); switch ($styleType) { case 'Alignment': @@ -750,15 +752,16 @@ class Xml extends BaseReader $diagonalDirection = ''; $borderPosition = ''; foreach ($styleData->Border as $borderStyle) { - $borderAttributes = $borderStyle->attributes($namespaces['ss']); + $borderAttributes = self::getAttributes($borderStyle, $namespaces['ss']); $thisBorder = []; $style = (string) $borderAttributes->Weight; $style .= strtolower((string) $borderAttributes->LineStyle); $thisBorder['borderStyle'] = self::$mappings['borderStyle'][$style] ?? Border::BORDER_NONE; - foreach ($borderAttributes as $borderStyleKey => $borderStyleValue) { + foreach ($borderAttributes as $borderStyleKey => $borderStyleValuex) { + $borderStyleValue = (string) $borderStyleValuex; switch ($borderStyleKey) { case 'Position': - $borderStyleValue = strtolower((string) $borderStyleValue); + $borderStyleValue = strtolower($borderStyleValue); if (in_array($borderStyleValue, self::$borderPositions)) { $borderPosition = $borderStyleValue; } elseif ($borderStyleValue == 'diagonalleft') { @@ -784,6 +787,11 @@ class Xml extends BaseReader } } + private static function getAttributes(?SimpleXMLElement $simple, string $node): SimpleXMLElement + { + return ($simple === null) ? new SimpleXMLElement('') : ($simple->attributes($node) ?? new SimpleXMLElement('')); + } + private static $underlineStyles = [ Font::UNDERLINE_NONE, Font::UNDERLINE_DOUBLE, @@ -854,7 +862,8 @@ class Xml extends BaseReader */ private function parseStyleInterior($styleID, SimpleXMLElement $styleAttributes): void { - foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) { + foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValuex) { + $styleAttributeValue = (string) $styleAttributeValuex; switch ($styleAttributeKey) { case 'Color': $this->styles[$styleID]['fill']['endColor']['rgb'] = substr($styleAttributeValue, 1); From fdc8e8d17a64274629524ac751f142369d876db7 Mon Sep 17 00:00:00 2001 From: Alexander Gunkel Date: Sun, 31 Jan 2021 18:26:50 +0100 Subject: [PATCH 030/187] Fix/1674 (#1688) * Treat inline strings like strings in Open Document because it has no specific inline-string format * implement data-type error Co-authored-by: Mark Baker --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Writer/Ods/Content.php | 11 +- .../Writer/Ods/ContentTest.php | 4 + tests/data/Writer/Ods/content-with-data.xml | 126 ++++++++++-------- 4 files changed, 78 insertions(+), 64 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24ddedc4..0cab5853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) - Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) +- Fix for not yet implemented data-types in Open Documend writer [Issue #1674](https://github.com/PHPOffice/PhpSpreadsheet/issues/1674) ## 1.16.0 - 2020-12-31 diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php index 96e66850..3222a9c7 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -196,7 +196,10 @@ class Content extends WriterPart break; case DataType::TYPE_ERROR: - throw new Exception('Writing of error not implemented yet.'); + $objWriter->writeAttribute('table:formula', 'of:=#NULL!'); + $objWriter->writeAttribute('office:value-type', 'string'); + $objWriter->writeAttribute('office:string-value', ''); + $objWriter->writeElement('text:p', '#NULL!'); break; case DataType::TYPE_FORMULA: @@ -217,10 +220,6 @@ class Content extends WriterPart $objWriter->writeAttribute('office:value', $formulaValue); $objWriter->writeElement('text:p', $formulaValue); - break; - case DataType::TYPE_INLINE: - throw new Exception('Writing of inline not implemented yet.'); - break; case DataType::TYPE_NUMERIC: $objWriter->writeAttribute('office:value-type', 'float'); @@ -228,6 +227,8 @@ class Content extends WriterPart $objWriter->writeElement('text:p', $cell->getValue()); break; + case DataType::TYPE_INLINE: + // break intentionally omitted case DataType::TYPE_STRING: $objWriter->writeAttribute('office:value-type', 'string'); $objWriter->writeElement('text:p', $cell->getValue()); diff --git a/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php b/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php index 4086914d..2ebd4984 100644 --- a/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php @@ -59,6 +59,7 @@ class ContentTest extends TestCase $worksheet1->setCellValue('A2', true); // Boolean $worksheet1->setCellValue('B2', false); // Boolean + $worksheet1->setCellValueExplicit( 'C2', '=IF(A3, CONCATENATE(A1, " ", A2), CONCATENATE(A2, " ", A1))', @@ -70,6 +71,9 @@ class ContentTest extends TestCase ->getNumberFormat() ->setFormatCode(NumberFormat::FORMAT_DATE_DATETIME); + $worksheet1->setCellValueExplicit('F1', null, DataType::TYPE_ERROR); + $worksheet1->setCellValueExplicit('G1', 'Lorem ipsum', DataType::TYPE_INLINE); + // Styles $worksheet1->getStyle('A1')->getFont()->setBold(true); $worksheet1->getStyle('B1')->getFont()->setItalic(true); diff --git a/tests/data/Writer/Ods/content-with-data.xml b/tests/data/Writer/Ods/content-with-data.xml index a9048047..a13ed0be 100644 --- a/tests/data/Writer/Ods/content-with-data.xml +++ b/tests/data/Writer/Ods/content-with-data.xml @@ -1,105 +1,113 @@ - - - - + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - + + - + 1 - + 12345.6789 - + 1 - + 01234 - + Lorem ipsum - + + #NULL! + + + Lorem ipsum + + - + 1 - - + + - + 1 1 - + 42798.572060185 - - + + + + - - + + - + 2 - + - + - \ No newline at end of file + From cade11f6685e5ca978ed1ca07b1e1689271dfe02 Mon Sep 17 00:00:00 2001 From: Gerrit Addiks Date: Sun, 31 Jan 2021 18:36:23 +0100 Subject: [PATCH 031/187] Fixed reading XSLS style alignments from XML (#1710) The attribute `$alignmentXml` given to the private method `readAlignmentStyle` is the alignment XML tag that contains the alignment data itself. But inside that method all data are read from another `alignment` XML tag within that given tag. This redundant child-node access resulted in the following error- / notice-message: `PHP Notice: Trying to access array offset on value of type null in /foo/bar/baz/vendor/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Reader/Xlsx/Styles.php on line 146` These changes remove the redundant child-node access in the method `readAlignmentStyle`. --- src/PhpSpreadsheet/Reader/Xlsx/Styles.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Styles.php b/src/PhpSpreadsheet/Reader/Xlsx/Styles.php index 43de8787..290e8cb7 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Styles.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Styles.php @@ -143,21 +143,21 @@ class Styles extends BaseParserClass private static function readAlignmentStyle(Alignment $alignment, SimpleXMLElement $alignmentXml): void { - $alignment->setHorizontal((string) $alignmentXml->alignment['horizontal']); - $alignment->setVertical((string) $alignmentXml->alignment['vertical']); + $alignment->setHorizontal((string) $alignmentXml['horizontal']); + $alignment->setVertical((string) $alignmentXml['vertical']); $textRotation = 0; - if ((int) $alignmentXml->alignment['textRotation'] <= 90) { - $textRotation = (int) $alignmentXml->alignment['textRotation']; - } elseif ((int) $alignmentXml->alignment['textRotation'] > 90) { - $textRotation = 90 - (int) $alignmentXml->alignment['textRotation']; + if ((int) $alignmentXml['textRotation'] <= 90) { + $textRotation = (int) $alignmentXml['textRotation']; + } elseif ((int) $alignmentXml['textRotation'] > 90) { + $textRotation = 90 - (int) $alignmentXml['textRotation']; } $alignment->setTextRotation((int) $textRotation); - $alignment->setWrapText(self::boolean((string) $alignmentXml->alignment['wrapText'])); - $alignment->setShrinkToFit(self::boolean((string) $alignmentXml->alignment['shrinkToFit'])); - $alignment->setIndent((int) ((string) $alignmentXml->alignment['indent']) > 0 ? (int) ((string) $alignmentXml->alignment['indent']) : 0); - $alignment->setReadOrder((int) ((string) $alignmentXml->alignment['readingOrder']) > 0 ? (int) ((string) $alignmentXml->alignment['readingOrder']) : 0); + $alignment->setWrapText(self::boolean((string) $alignmentXml['wrapText'])); + $alignment->setShrinkToFit(self::boolean((string) $alignmentXml['shrinkToFit'])); + $alignment->setIndent((int) ((string) $alignmentXml['indent']) > 0 ? (int) ((string) $alignmentXml['indent']) : 0); + $alignment->setReadOrder((int) ((string) $alignmentXml['readingOrder']) > 0 ? (int) ((string) $alignmentXml['readingOrder']) : 0); } private function readStyle(Style $docStyle, $style): void From 304904d829b12f408fe6ff201639f260941f2d98 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 31 Jan 2021 18:39:02 +0100 Subject: [PATCH 032/187] Update change log --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cab5853..efcb21ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,7 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) - Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) -- Fix for not yet implemented data-types in Open Documend writer [Issue #1674](https://github.com/PHPOffice/PhpSpreadsheet/issues/1674) +- Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) +- Fix for not yet implemented data-types in Open Document writer [Issue #1674](https://github.com/PHPOffice/PhpSpreadsheet/issues/1674) ## 1.16.0 - 2020-12-31 From 44248cd04ef8bb78235e5fb44c79d773725522cc Mon Sep 17 00:00:00 2001 From: Darren Maczka Date: Sun, 31 Jan 2021 12:53:54 -0500 Subject: [PATCH 033/187] Fix/sheets xlsx chart (#1761) * Add support for Google Sheets Exported XLSX Charts Google Sheets XLSX charts use oneCellAnchor positioning and the data series do not have the *Cache elements with cached values. * update CHANGELOG * Add support for Google Sheets Exported XLSX Charts Google Sheets XLSX charts use oneCellAnchor positioning and the data series do not have the *Cache elements with cached values. Because the reader had been assuming *Cache elements existed as children of strRef and numRef, errors about the node being deleted were thrown when reading Xlsx exported from Google Sheets. Co-authored-by: Darren Maczka --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Reader/Xlsx.php | 23 ++++++-- src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 45 ++++++++++++---- .../Reader/SheetsXlsxChartTest.php | 51 ++++++++++++++++++ tests/data/Reader/XLSX/sheetsChartsTest.xlsx | Bin 0 -> 12042 bytes 5 files changed, 107 insertions(+), 13 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php create mode 100755 tests/data/Reader/XLSX/sheetsChartsTest.xlsx diff --git a/CHANGELOG.md b/CHANGELOG.md index efcb21ca..d429f0ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. - Fix for Xls Reader when SST has a bad length [#1592](https://github.com/PHPOffice/PhpSpreadsheet/issues/1592) - Resolve Xlsx loader issue whe hyperlinks don't have a destination - Resolve issues when printer settings resources IDs clash with drawing IDs diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index c05f77de..c228f344 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -1155,13 +1155,27 @@ class Xlsx extends BaseReader $this->readHyperLinkDrawing($objDrawing, $oneCellAnchor, $hyperlinks); $objDrawing->setWorksheet($docSheet); - } else { - // ? Can charts be positioned with a oneCellAnchor ? + } elseif ($this->includeCharts && $oneCellAnchor->graphicFrame) { + // Exported XLSX from Google Sheets positions charts with a oneCellAnchor $coordinates = Coordinate::stringFromColumnIndex(((string) $oneCellAnchor->from->col) + 1) . ($oneCellAnchor->from->row + 1); $offsetX = Drawing::EMUToPixels($oneCellAnchor->from->colOff); $offsetY = Drawing::EMUToPixels($oneCellAnchor->from->rowOff); $width = Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cx')); $height = Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cy')); + + $graphic = $oneCellAnchor->graphicFrame->children('http://schemas.openxmlformats.org/drawingml/2006/main')->graphic; + /** @var SimpleXMLElement $chartRef */ + $chartRef = $graphic->graphicData->children('http://schemas.openxmlformats.org/drawingml/2006/chart')->chart; + $thisChart = (string) $chartRef->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + + $chartDetails[$docSheet->getTitle() . '!' . $thisChart] = [ + 'fromCoordinate' => $coordinates, + 'fromOffsetX' => $offsetX, + 'fromOffsetY' => $offsetY, + 'width' => $width, + 'height' => $height, + 'worksheetTitle' => $docSheet->getTitle(), + ]; } } } @@ -1508,7 +1522,10 @@ class Xlsx extends BaseReader $excel->getSheetByName($charts[$chartEntryRef]['sheet'])->addChart($objChart); $objChart->setWorksheet($excel->getSheetByName($charts[$chartEntryRef]['sheet'])); $objChart->setTopLeftPosition($chartDetails[$chartPositionRef]['fromCoordinate'], $chartDetails[$chartPositionRef]['fromOffsetX'], $chartDetails[$chartPositionRef]['fromOffsetY']); - $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']); + if (array_key_exists('toCoordinate', $chartDetails[$chartPositionRef])) { + // For oneCellAnchor positioned charts, toCoordinate is not in the data. Does it need to be calculated? + $objChart->setBottomRightPosition($chartDetails[$chartPositionRef]['toCoordinate'], $chartDetails[$chartPositionRef]['toOffsetX'], $chartDetails[$chartPositionRef]['toOffsetY']); + } } } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index c9a230c2..84b2e62b 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -328,26 +328,51 @@ class Chart { if (isset($seriesDetail->strRef)) { $seriesSource = (string) $seriesDetail->strRef->f; - $seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's'); + $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker); - return new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker); + if (isset($seriesDetail->strRef->strCache)) { + $seriesData = self::chartDataSeriesValues($seriesDetail->strRef->strCache->children($namespacesChartMeta['c']), 's'); + $seriesValues + ->setFormatCode($seriesData['formatCode']) + ->setDataValues($seriesData['dataValues']); + } + + return $seriesValues; } elseif (isset($seriesDetail->numRef)) { $seriesSource = (string) $seriesDetail->numRef->f; - $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c'])); + $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, null, null, $marker); + if (isset($seriesDetail->strRef->strCache)) { + $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c'])); + $seriesValues + ->setFormatCode($seriesData['formatCode']) + ->setDataValues($seriesData['dataValues']); + } - return new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker); + return $seriesValues; } elseif (isset($seriesDetail->multiLvlStrRef)) { $seriesSource = (string) $seriesDetail->multiLvlStrRef->f; - $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's'); - $seriesData['pointCount'] = count($seriesData['dataValues']); + $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker); - return new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker); + if (isset($seriesDetail->multiLvlStrRef->multiLvlStrCache)) { + $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($namespacesChartMeta['c']), 's'); + $seriesValues + ->setFormatCode($seriesData['formatCode']) + ->setDataValues($seriesData['dataValues']); + } + + return $seriesValues; } elseif (isset($seriesDetail->multiLvlNumRef)) { $seriesSource = (string) $seriesDetail->multiLvlNumRef->f; - $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's'); - $seriesData['pointCount'] = count($seriesData['dataValues']); + $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, null, null, $marker); - return new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, $seriesData['formatCode'], $seriesData['pointCount'], $seriesData['dataValues'], $marker); + if (isset($seriesDetail->multiLvlNumRef->multiLvlNumCache)) { + $seriesData = self::chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($namespacesChartMeta['c']), 's'); + $seriesValues + ->setFormatCode($seriesData['formatCode']) + ->setDataValues($seriesData['dataValues']); + } + + return $seriesValues; } return null; diff --git a/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php b/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php new file mode 100644 index 00000000..c4dc328d --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/SheetsXlsxChartTest.php @@ -0,0 +1,51 @@ +setIncludeCharts(true); + $spreadsheet = $reader->load($filename); + $worksheet = $spreadsheet->getActiveSheet(); + + $charts = $worksheet->getChartCollection(); + self::assertEquals(2, $worksheet->getChartCount()); + self::assertCount(2, $charts); + + $chart1 = $charts[0]; + $pa1 = $chart1->getPlotArea(); + self::assertEquals(2, $pa1->getPlotSeriesCount()); + + $pg1 = $pa1->getPlotGroup()[0]; + + self::assertEquals(DataSeries::TYPE_LINECHART, $pg1->getPlotType()); + self::assertCount(2, $pg1->getPlotLabels()); + self::assertCount(2, $pg1->getPlotValues()); + self::assertCount(2, $pg1->getPlotCategories()); + + $chart2 = $charts[1]; + $pa1 = $chart2->getPlotArea(); + self::assertEquals(2, $pa1->getPlotSeriesCount()); + + $pg1 = $pa1->getPlotGroupByIndex(0); + //Before a refresh, data values are empty + foreach ($pg1->getPlotValues() as $dv) { + self::assertEmpty($dv->getPointCount()); + } + $pg1->refresh($worksheet); + foreach ($pg1->getPlotValues() as $dv) { + self::assertEquals(9, $dv->getPointCount()); + } + self::assertEquals(DataSeries::TYPE_SCATTERCHART, $pg1->getPlotType()); + self::assertCount(2, $pg1->getPlotLabels()); + self::assertCount(2, $pg1->getPlotValues()); + self::assertCount(2, $pg1->getPlotCategories()); + } +} diff --git a/tests/data/Reader/XLSX/sheetsChartsTest.xlsx b/tests/data/Reader/XLSX/sheetsChartsTest.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..82e00ac932844cc1fa060fd08f84bfb2ea56ec70 GIT binary patch literal 12042 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 Date: Sun, 31 Jan 2021 13:13:50 -0500 Subject: [PATCH 034/187] Fix/chart axis titles (#1760) * use axPos value to determine whether an axis title is mapped to the XaxisLabel or YaxisLabel * update changelog * Fix php-cs-fixer violations Co-authored-by: Darren Maczka Co-authored-by: Mark Baker --- CHANGELOG.md | 3 +- src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 16 ++++- .../Reader/Xlsx/ChartsTitleTest.php | 64 ++++++++++++++++++ tests/data/Reader/XLSX/excelChartsTest.xlsx | Bin 0 -> 32243 bytes 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php create mode 100644 tests/data/Reader/XLSX/excelChartsTest.xlsx diff --git a/CHANGELOG.md b/CHANGELOG.md index d429f0ad..dc1a809d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fix for Xlsx Chart axis titles mapping to correct X or Y axis label when only one is present. +- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) - Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) - Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) @@ -58,7 +60,6 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. - Fix for Xls Reader when SST has a bad length [#1592](https://github.com/PHPOffice/PhpSpreadsheet/issues/1592) - Resolve Xlsx loader issue whe hyperlinks don't have a destination - Resolve issues when printer settings resources IDs clash with drawing IDs diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index 84b2e62b..5a3439f2 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -91,7 +91,21 @@ class Chart break; case 'valAx': if (isset($chartDetail->title)) { - $YaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); + $axisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); + $axPos = self::getAttribute($chartDetail->axPos, 'val', 'string'); + + switch ($axPos) { + case 't': + case 'b': + $XaxisLabel = $axisLabel; + + break; + case 'r': + case 'l': + $YaxisLabel = $axisLabel; + + break; + } } break; diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php new file mode 100644 index 00000000..5e171139 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php @@ -0,0 +1,64 @@ +getCaption()) { + return null; + } + + return implode("\n", array_map(function ($rt) { + return $rt->getPlainText(); + }, $title->getCaption())); +} + +class ChartsTitleTest extends TestCase +{ + public function testChartTitles(): void + { + $filename = 'tests/data/Reader/XLSX/excelChartsTest.xlsx'; + $reader = IOFactory::createReader('Xlsx')->setIncludeCharts(true); + $spreadsheet = $reader->load($filename); + $worksheet = $spreadsheet->getActiveSheet(); + + $charts = $worksheet->getChartCollection(); + self::assertEquals(5, $worksheet->getChartCount()); + self::assertCount(5, $charts); + + // No title or axis labels + $chart1 = $charts[0]; + $title = getTitleText($chart1->getTitle()); + self::assertEmpty($title); + self::assertEmpty(getTitleText($chart1->getXAxisLabel())); + self::assertEmpty(getTitleText($chart1->getYAxisLabel())); + + // Title, no axis labels + $chart2 = $charts[1]; + + self::assertEquals('Chart with Title and no Axis Labels', getTitleText($chart2->getTitle())); + self::assertEmpty(getTitleText($chart2->getXAxisLabel())); + self::assertEmpty(getTitleText($chart2->getYAxisLabel())); + + // No title, only horizontal axis label + $chart3 = $charts[2]; + self::assertEmpty(getTitleText($chart3->getTitle())); + self::assertEquals('Horizontal Axis Title Only', getTitleText($chart3->getXAxisLabel())); + self::assertEmpty(getTitleText($chart3->getYAxisLabel())); + + // No title, only vertical axis label + $chart4 = $charts[3]; + self::assertEmpty(getTitleText($chart4->getTitle())); + self::assertEquals('Vertical Axis Title Only', getTitleText($chart4->getYAxisLabel())); + self::assertEmpty(getTitleText($chart4->getXAxisLabel())); + + // Title and both axis labels + $chart5 = $charts[4]; + self::assertEquals('Complete Annotations', getTitleText($chart5->getTitle())); + self::assertEquals('Horizontal Axis Title', getTitleText($chart5->getXAxisLabel())); + self::assertEquals('Vertical Axis Title', getTitleText($chart5->getYAxisLabel())); + } +} diff --git a/tests/data/Reader/XLSX/excelChartsTest.xlsx b/tests/data/Reader/XLSX/excelChartsTest.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..78cbc8f90250aca9faa05c167fe7e72fb38080c7 GIT binary patch literal 32243 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 P^cNdCQvkdC`0IZFH~@3B literal 0 HcmV?d00001 From 8b94a37e23ec7083bf6e3a8c70af70f0d373f040 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 31 Jan 2021 19:16:42 +0100 Subject: [PATCH 035/187] Update change log --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc1a809d..dda1af25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,8 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Fix for Xlsx Chart axis titles mapping to correct X or Y axis label when only one is present. -- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. +- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. [PR #1761](https://github.com/PHPOffice/PhpSpreadsheet/pull/1761) +- Fix for Xlsx Chart axis titles mapping to correct X or Y axis label when only one is present. [PR #1760](https://github.com/PHPOffice/PhpSpreadsheet/pull/1760) - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) - Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) - Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) From 5f761b62740d55f2987b47639b807eab5c0ce7a4 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 31 Jan 2021 23:39:37 +0100 Subject: [PATCH 036/187] Cell alignment for ods Writer (#1819) * Cell alignment for ods Writer --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Writer/Ods/Content.php | 105 +++++++++++++++----- tests/data/Writer/Ods/content-empty.xml | 3 +- tests/data/Writer/Ods/content-with-data.xml | 33 ++++-- 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dda1af25..5c0f089a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) - CSV Reader - Best Guess for Encoding, and Handle Null-string Escape [#1647](https://github.com/PHPOffice/PhpSpreadsheet/issues/1647) ### Changed diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php index 3222a9c7..f66225c5 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -7,6 +7,7 @@ use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Style\Alignment; use PhpOffice\PhpSpreadsheet\Style\Fill; use PhpOffice\PhpSpreadsheet\Style\Font; use PhpOffice\PhpSpreadsheet\Worksheet\Row; @@ -270,6 +271,38 @@ class Content extends WriterPart } } + private function mapHorizontalAlignment(string $horizontalAlignment): string + { + switch ($horizontalAlignment) { + case Alignment::HORIZONTAL_CENTER: + case Alignment::HORIZONTAL_CENTER_CONTINUOUS: + case Alignment::HORIZONTAL_DISTRIBUTED: + return 'center'; + case Alignment::HORIZONTAL_RIGHT: + return 'end'; + case Alignment::HORIZONTAL_FILL: + case Alignment::HORIZONTAL_JUSTIFY: + return 'justify'; + } + + return 'start'; + } + + private function mapVerticalAlignment(string $verticalAlignment): string + { + switch ($verticalAlignment) { + case Alignment::VERTICAL_TOP: + return 'top'; + case Alignment::VERTICAL_CENTER: + return 'middle'; + case Alignment::VERTICAL_DISTRIBUTED: + case Alignment::VERTICAL_JUSTIFY: + return 'automatic'; + } + + return 'bottom'; + } + /** * Write XF cell styles. */ @@ -281,6 +314,51 @@ class Content extends WriterPart $writer->writeAttribute('style:family', 'table-cell'); $writer->writeAttribute('style:parent-style-name', 'Default'); + // Align + $hAlign = $style->getAlignment()->getHorizontal(); + $vAlign = $style->getAlignment()->getVertical(); + $wrap = $style->getAlignment()->getWrapText(); + + $writer->startElement('style:table-cell-properties'); + if (!empty($vAlign) || $wrap) { + if (!empty($vAlign)) { + $vAlign = $this->mapVerticalAlignment($vAlign); + $writer->writeAttribute('style:vertical-align', $vAlign); + } + if ($wrap) { + $writer->writeAttribute('fo:wrap-option', 'wrap'); + } + } + $writer->writeAttribute('style:rotation-align', 'none'); + + // Fill + if ($fill = $style->getFill()) { + switch ($fill->getFillType()) { + case Fill::FILL_SOLID: + $writer->writeAttribute('fo:background-color', sprintf( + '#%s', + strtolower($fill->getStartColor()->getRGB()) + )); + + break; + case Fill::FILL_GRADIENT_LINEAR: + case Fill::FILL_GRADIENT_PATH: + /// TODO :: To be implemented + break; + case Fill::FILL_NONE: + default: + } + } + + $writer->endElement(); + + if (!empty($hAlign)) { + $hAlign = $this->mapHorizontalAlignment($hAlign); + $writer->startElement('style:paragraph-properties'); + $writer->writeAttribute('fo:text-align', $hAlign); + $writer->endElement(); + } + // style:text-properties // Font @@ -329,34 +407,7 @@ class Content extends WriterPart $writer->endElement(); // Close style:text-properties - // style:table-cell-properties - - $writer->startElement('style:table-cell-properties'); - $writer->writeAttribute('style:rotation-align', 'none'); - - // Fill - if ($fill = $style->getFill()) { - switch ($fill->getFillType()) { - case Fill::FILL_SOLID: - $writer->writeAttribute('fo:background-color', sprintf( - '#%s', - strtolower($fill->getStartColor()->getRGB()) - )); - - break; - case Fill::FILL_GRADIENT_LINEAR: - case Fill::FILL_GRADIENT_PATH: - /// TODO :: To be implemented - break; - case Fill::FILL_NONE: - default: - } - } - - $writer->endElement(); // Close style:table-cell-properties - // End - $writer->endElement(); // Close style:style } } diff --git a/tests/data/Writer/Ods/content-empty.xml b/tests/data/Writer/Ods/content-empty.xml index 87f756db..c9620060 100644 --- a/tests/data/Writer/Ods/content-empty.xml +++ b/tests/data/Writer/Ods/content-empty.xml @@ -4,8 +4,9 @@ + + - diff --git a/tests/data/Writer/Ods/content-with-data.xml b/tests/data/Writer/Ods/content-with-data.xml index a13ed0be..a707d197 100644 --- a/tests/data/Writer/Ods/content-with-data.xml +++ b/tests/data/Writer/Ods/content-with-data.xml @@ -4,48 +4,59 @@ + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - From d28b7de1fcffa2a45bdf1ee619e3549d285d8548 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 1 Feb 2021 05:01:00 +0100 Subject: [PATCH 037/187] Refactoring of ODS Writer to break codebase into smaller components (#1820) * Refactoring of ODS Writer to break codebase into smaller components --- src/PhpSpreadsheet/Writer/Ods/Cell/Style.php | 178 +++++++++++++++++++ src/PhpSpreadsheet/Writer/Ods/Content.php | 143 +-------------- 2 files changed, 183 insertions(+), 138 deletions(-) create mode 100644 src/PhpSpreadsheet/Writer/Ods/Cell/Style.php diff --git a/src/PhpSpreadsheet/Writer/Ods/Cell/Style.php b/src/PhpSpreadsheet/Writer/Ods/Cell/Style.php new file mode 100644 index 00000000..f8aae20c --- /dev/null +++ b/src/PhpSpreadsheet/Writer/Ods/Cell/Style.php @@ -0,0 +1,178 @@ +writer = $writer; + } + + private function mapHorizontalAlignment(string $horizontalAlignment): string + { + switch ($horizontalAlignment) { + case Alignment::HORIZONTAL_CENTER: + case Alignment::HORIZONTAL_CENTER_CONTINUOUS: + case Alignment::HORIZONTAL_DISTRIBUTED: + return 'center'; + case Alignment::HORIZONTAL_RIGHT: + return 'end'; + case Alignment::HORIZONTAL_FILL: + case Alignment::HORIZONTAL_JUSTIFY: + return 'justify'; + } + + return 'start'; + } + + private function mapVerticalAlignment(string $verticalAlignment): string + { + switch ($verticalAlignment) { + case Alignment::VERTICAL_TOP: + return 'top'; + case Alignment::VERTICAL_CENTER: + return 'middle'; + case Alignment::VERTICAL_DISTRIBUTED: + case Alignment::VERTICAL_JUSTIFY: + return 'automatic'; + } + + return 'bottom'; + } + + private function writeFillStyle(Fill $fill): void + { + switch ($fill->getFillType()) { + case Fill::FILL_SOLID: + $this->writer->writeAttribute('fo:background-color', sprintf( + '#%s', + strtolower($fill->getStartColor()->getRGB()) + )); + + break; + case Fill::FILL_GRADIENT_LINEAR: + case Fill::FILL_GRADIENT_PATH: + /// TODO :: To be implemented + break; + case Fill::FILL_NONE: + default: + } + } + + private function writeCellProperties(CellStyle $style): void + { + // Align + $hAlign = $style->getAlignment()->getHorizontal(); + $vAlign = $style->getAlignment()->getVertical(); + $wrap = $style->getAlignment()->getWrapText(); + + $this->writer->startElement('style:table-cell-properties'); + if (!empty($vAlign) || $wrap) { + if (!empty($vAlign)) { + $vAlign = $this->mapVerticalAlignment($vAlign); + $this->writer->writeAttribute('style:vertical-align', $vAlign); + } + if ($wrap) { + $this->writer->writeAttribute('fo:wrap-option', 'wrap'); + } + } + $this->writer->writeAttribute('style:rotation-align', 'none'); + + // Fill + if ($fill = $style->getFill()) { + $this->writeFillStyle($fill); + } + + $this->writer->endElement(); + + if (!empty($hAlign)) { + $hAlign = $this->mapHorizontalAlignment($hAlign); + $this->writer->startElement('style:paragraph-properties'); + $this->writer->writeAttribute('fo:text-align', $hAlign); + $this->writer->endElement(); + } + } + + protected function mapUnderlineStyle(Font $font): string + { + switch ($font->getUnderline()) { + case Font::UNDERLINE_DOUBLE: + case Font::UNDERLINE_DOUBLEACCOUNTING: + return'double'; + case Font::UNDERLINE_SINGLE: + case Font::UNDERLINE_SINGLEACCOUNTING: + return'single'; + } + + return 'none'; + } + + protected function writeTextProperties(CellStyle $style): void + { + // Font + $this->writer->startElement('style:text-properties'); + + $font = $style->getFont(); + + if ($font->getBold()) { + $this->writer->writeAttribute('fo:font-weight', 'bold'); + $this->writer->writeAttribute('style:font-weight-complex', 'bold'); + $this->writer->writeAttribute('style:font-weight-asian', 'bold'); + } + + if ($font->getItalic()) { + $this->writer->writeAttribute('fo:font-style', 'italic'); + } + + if ($color = $font->getColor()) { + $this->writer->writeAttribute('fo:color', sprintf('#%s', $color->getRGB())); + } + + if ($family = $font->getName()) { + $this->writer->writeAttribute('fo:font-family', $family); + } + + if ($size = $font->getSize()) { + $this->writer->writeAttribute('fo:font-size', sprintf('%.1Fpt', $size)); + } + + if ($font->getUnderline() && $font->getUnderline() !== Font::UNDERLINE_NONE) { + $this->writer->writeAttribute('style:text-underline-style', 'solid'); + $this->writer->writeAttribute('style:text-underline-width', 'auto'); + $this->writer->writeAttribute('style:text-underline-color', 'font-color'); + + $underline = $this->mapUnderlineStyle($font); + $this->writer->writeAttribute('style:text-underline-type', $underline); + } + + $this->writer->endElement(); // Close style:text-properties + } + + public function write(CellStyle $style): void + { + $this->writer->startElement('style:style'); + $this->writer->writeAttribute('style:name', self::CELL_STYLE_PREFIX . $style->getIndex()); + $this->writer->writeAttribute('style:family', 'table-cell'); + $this->writer->writeAttribute('style:parent-style-name', 'Default'); + + // Alignment, fill colour, etc + $this->writeCellProperties($style); + + // style:text-properties + $this->writeTextProperties($style); + + // End + $this->writer->endElement(); // Close style:style + } +} diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php index f66225c5..10238ebf 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -7,14 +7,12 @@ use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PhpOffice\PhpSpreadsheet\Style\Alignment; -use PhpOffice\PhpSpreadsheet\Style\Fill; -use PhpOffice\PhpSpreadsheet\Style\Font; use PhpOffice\PhpSpreadsheet\Worksheet\Row; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PhpOffice\PhpSpreadsheet\Writer\Exception; use PhpOffice\PhpSpreadsheet\Writer\Ods; use PhpOffice\PhpSpreadsheet\Writer\Ods\Cell\Comment; +use PhpOffice\PhpSpreadsheet\Writer\Ods\Cell\Style; /** * @author Alexander Pervakov @@ -23,7 +21,6 @@ class Content extends WriterPart { const NUMBER_COLS_REPEATED_MAX = 1024; const NUMBER_ROWS_REPEATED_MAX = 1048576; - const CELL_STYLE_PREFIX = 'ce'; private $formulaConvertor; @@ -186,7 +183,7 @@ class Content extends WriterPart // Style XF $style = $cell->getXfIndex(); if ($style !== null) { - $objWriter->writeAttribute('table:style-name', self::CELL_STYLE_PREFIX . $style); + $objWriter->writeAttribute('table:style-name', Style::CELL_STYLE_PREFIX . $style); } switch ($cell->getDataType()) { @@ -271,144 +268,14 @@ class Content extends WriterPart } } - private function mapHorizontalAlignment(string $horizontalAlignment): string - { - switch ($horizontalAlignment) { - case Alignment::HORIZONTAL_CENTER: - case Alignment::HORIZONTAL_CENTER_CONTINUOUS: - case Alignment::HORIZONTAL_DISTRIBUTED: - return 'center'; - case Alignment::HORIZONTAL_RIGHT: - return 'end'; - case Alignment::HORIZONTAL_FILL: - case Alignment::HORIZONTAL_JUSTIFY: - return 'justify'; - } - - return 'start'; - } - - private function mapVerticalAlignment(string $verticalAlignment): string - { - switch ($verticalAlignment) { - case Alignment::VERTICAL_TOP: - return 'top'; - case Alignment::VERTICAL_CENTER: - return 'middle'; - case Alignment::VERTICAL_DISTRIBUTED: - case Alignment::VERTICAL_JUSTIFY: - return 'automatic'; - } - - return 'bottom'; - } - /** * Write XF cell styles. */ private function writeXfStyles(XMLWriter $writer, Spreadsheet $spreadsheet): void { + $styleWriter = new Style($writer); foreach ($spreadsheet->getCellXfCollection() as $style) { - $writer->startElement('style:style'); - $writer->writeAttribute('style:name', self::CELL_STYLE_PREFIX . $style->getIndex()); - $writer->writeAttribute('style:family', 'table-cell'); - $writer->writeAttribute('style:parent-style-name', 'Default'); - - // Align - $hAlign = $style->getAlignment()->getHorizontal(); - $vAlign = $style->getAlignment()->getVertical(); - $wrap = $style->getAlignment()->getWrapText(); - - $writer->startElement('style:table-cell-properties'); - if (!empty($vAlign) || $wrap) { - if (!empty($vAlign)) { - $vAlign = $this->mapVerticalAlignment($vAlign); - $writer->writeAttribute('style:vertical-align', $vAlign); - } - if ($wrap) { - $writer->writeAttribute('fo:wrap-option', 'wrap'); - } - } - $writer->writeAttribute('style:rotation-align', 'none'); - - // Fill - if ($fill = $style->getFill()) { - switch ($fill->getFillType()) { - case Fill::FILL_SOLID: - $writer->writeAttribute('fo:background-color', sprintf( - '#%s', - strtolower($fill->getStartColor()->getRGB()) - )); - - break; - case Fill::FILL_GRADIENT_LINEAR: - case Fill::FILL_GRADIENT_PATH: - /// TODO :: To be implemented - break; - case Fill::FILL_NONE: - default: - } - } - - $writer->endElement(); - - if (!empty($hAlign)) { - $hAlign = $this->mapHorizontalAlignment($hAlign); - $writer->startElement('style:paragraph-properties'); - $writer->writeAttribute('fo:text-align', $hAlign); - $writer->endElement(); - } - - // style:text-properties - - // Font - $writer->startElement('style:text-properties'); - - $font = $style->getFont(); - - if ($font->getBold()) { - $writer->writeAttribute('fo:font-weight', 'bold'); - $writer->writeAttribute('style:font-weight-complex', 'bold'); - $writer->writeAttribute('style:font-weight-asian', 'bold'); - } - - if ($font->getItalic()) { - $writer->writeAttribute('fo:font-style', 'italic'); - } - - if ($color = $font->getColor()) { - $writer->writeAttribute('fo:color', sprintf('#%s', $color->getRGB())); - } - - if ($family = $font->getName()) { - $writer->writeAttribute('fo:font-family', $family); - } - - if ($size = $font->getSize()) { - $writer->writeAttribute('fo:font-size', sprintf('%.1Fpt', $size)); - } - - if ($font->getUnderline() && $font->getUnderline() != Font::UNDERLINE_NONE) { - $writer->writeAttribute('style:text-underline-style', 'solid'); - $writer->writeAttribute('style:text-underline-width', 'auto'); - $writer->writeAttribute('style:text-underline-color', 'font-color'); - - switch ($font->getUnderline()) { - case Font::UNDERLINE_DOUBLE: - $writer->writeAttribute('style:text-underline-type', 'double'); - - break; - case Font::UNDERLINE_SINGLE: - $writer->writeAttribute('style:text-underline-type', 'single'); - - break; - } - } - - $writer->endElement(); // Close style:text-properties - - // End - $writer->endElement(); // Close style:style + $styleWriter->write($style); } } @@ -426,7 +293,7 @@ class Content extends WriterPart $start = Coordinate::coordinateFromString($startCell); $end = Coordinate::coordinateFromString($endCell); $columnSpan = Coordinate::columnIndexFromString($end[0]) - Coordinate::columnIndexFromString($start[0]) + 1; - $rowSpan = $end[1] - $start[1] + 1; + $rowSpan = ((int) $end[1]) - ((int) $start[1]) + 1; $objWriter->writeAttribute('table:number-columns-spanned', $columnSpan); $objWriter->writeAttribute('table:number-rows-spanned', $rowSpan); From fa51a8590bf7d08f34ce14877605841859955bce Mon Sep 17 00:00:00 2001 From: Roland Eigelsreiter Date: Mon, 1 Feb 2021 11:56:27 +0100 Subject: [PATCH 038/187] Fix XLSX reader when having a corrupt numeric cell data type (#1664) * fix for read xlsx with somewhat corrupt cell data type --- CHANGELOG.md | 3 ++- src/PhpSpreadsheet/Reader/Xlsx.php | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c0f089a..4c6a3fef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,6 +128,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Reader/Gnumeric Failure with PHP8 [#1662](https://github.com/phpoffice/phpspreadsheet/pull/1662) - ReverseSort bug, exposed but not caused by PHP8 [#1660](https://github.com/phpoffice/phpspreadsheet/pull/1660) - Bug setting Superscript/Subscript to false [#1567](https://github.com/phpoffice/phpspreadsheet/pull/1567) +- Fix XLSX reader when having a corrupt numeric cell data type [#1664](https://github.com/phpoffice/phpspreadsheet/pull/1664) ## 1.14.1 - 2020-07-19 @@ -656,4 +657,4 @@ For a comprehensive list of all class changes, and a semi-automated migration pa ## Previous versions of PHPExcel -The changelog for the project when it was called PHPExcel is [still available](./CHANGELOG.PHPExcel.md). +The changelog for the project when it was called PHPExcel is [still available](./CHANGELOG.PHPExcel.md). \ No newline at end of file diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index c228f344..432e9d2a 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\Hyperlink; use PhpOffice\PhpSpreadsheet\DefinedName; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; @@ -735,6 +736,10 @@ class Xlsx extends BaseReader $cell = $docSheet->getCell($r); // Assign value if ($cellDataType != '') { + // it is possible, that datatype is numeric but with an empty string, which result in an error + if ($cellDataType === DataType::TYPE_NUMERIC && $value === '') { + $cellDataType = DataType::TYPE_STRING; + } $cell->setValueExplicit($value, $cellDataType); } else { $cell->setValue($value); From a184b0f37bcf1d27d4a01a36677c295ccaa73edb Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 1 Feb 2021 11:58:40 +0100 Subject: [PATCH 039/187] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c6a3fef..c666257d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) - Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) - Fix for not yet implemented data-types in Open Document writer [Issue #1674](https://github.com/PHPOffice/PhpSpreadsheet/issues/1674) +- Fix XLSX reader when having a corrupt numeric cell data type [PR #1664](https://github.com/phpoffice/phpspreadsheet/pull/1664) ## 1.16.0 - 2020-12-31 @@ -128,7 +129,6 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Reader/Gnumeric Failure with PHP8 [#1662](https://github.com/phpoffice/phpspreadsheet/pull/1662) - ReverseSort bug, exposed but not caused by PHP8 [#1660](https://github.com/phpoffice/phpspreadsheet/pull/1660) - Bug setting Superscript/Subscript to false [#1567](https://github.com/phpoffice/phpspreadsheet/pull/1567) -- Fix XLSX reader when having a corrupt numeric cell data type [#1664](https://github.com/phpoffice/phpspreadsheet/pull/1664) ## 1.14.1 - 2020-07-19 From ce79f17fa98ec26dae8c8024447a01cf2980f002 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 1 Feb 2021 14:27:00 +0100 Subject: [PATCH 040/187] Update changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c666257d..181fb846 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added - Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754) +- Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) ### Changed @@ -21,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). `RADIANS()` (deg2rad), `SIN()`, `SINH()`, `SQRT()`, `TAN()`, `TANH()`. One TextData function is also affected: `REPT()` (str_repeat). +- `formatAsDate` correctly matches language metadata, reverting c55272e ### Deprecated @@ -44,13 +46,11 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) - CSV Reader - Best Guess for Encoding, and Handle Null-string Escape [#1647](https://github.com/PHPOffice/PhpSpreadsheet/issues/1647) ### Changed - Updated the CONVERT() function to support all current MS Excel categories and Units of Measure. -- `formatAsDate` correctly matches language metadata, reverting c55272e ### Deprecated From 30717fd35a768c8d02634863661fe909f142fbce Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 2 Feb 2021 15:16:03 +0900 Subject: [PATCH 041/187] Remove leftover of Sami --- .gitattributes | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 19c90f40..9f2b2f6e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,7 +3,6 @@ /.github export-ignore /.gitignore export-ignore /.php_cs.dist export-ignore -/.sami.php export-ignore /.scrutinizer.yml export-ignore /CHANGELOG.PHPExcel.md export-ignore /bin export-ignore From 2fac9ee2f7744b38fc64981a06cc2e35f8e3f47d Mon Sep 17 00:00:00 2001 From: oleibman Date: Wed, 3 Feb 2021 14:53:04 -0800 Subject: [PATCH 042/187] Stacked Alignment - Use Class Constant Rather than Literal (#1716) * Stacked Alignment - Use Class Constant Rather than Literal PR #1580 defined constants for "stacked" alignment in cells. Using those constants outside of Style/Alignment was beyond the scope of the original PR, but I said I would get to it. This PR replaces all uses of literal -165, and appropriate uses of literal 255, with the named constants, and adds tests to make sure that the changed code is covered in the test suite. --- samples/Basic/30_Templatebiff5.php | 43 ++++++++++ samples/templates/30template.xls | Bin 39424 -> 51200 bytes samples/templates/30templatebiff5.xls | Bin 0 -> 338944 bytes src/PhpSpreadsheet/Reader/Xls.php | 6 +- src/PhpSpreadsheet/Shared/Font.php | 3 +- src/PhpSpreadsheet/Writer/Xls/Xf.php | 75 +++++++----------- .../Functional/ActiveSheetTest.php | 7 ++ tests/PhpSpreadsheetTests/Shared/FontTest.php | 13 +++ 8 files changed, 95 insertions(+), 52 deletions(-) create mode 100644 samples/Basic/30_Templatebiff5.php create mode 100644 samples/templates/30templatebiff5.xls diff --git a/samples/Basic/30_Templatebiff5.php b/samples/Basic/30_Templatebiff5.php new file mode 100644 index 00000000..53c4c2a8 --- /dev/null +++ b/samples/Basic/30_Templatebiff5.php @@ -0,0 +1,43 @@ +log('Load from Xls template'); +$reader = IOFactory::createReader('Xls'); +$spreadsheet = $reader->load(__DIR__ . '/../templates/30templatebiff5.xls'); + +$helper->log('Add new data to the template'); +$data = [['title' => 'Excel for dummies', + 'price' => 17.99, + 'quantity' => 2, +], + ['title' => 'PHP for dummies', + 'price' => 15.99, + 'quantity' => 1, + ], + ['title' => 'Inside OOP', + 'price' => 12.95, + 'quantity' => 1, + ], +]; + +$spreadsheet->getActiveSheet()->setCellValue('D1', Date::PHPToExcel(time())); + +$baseRow = 5; +foreach ($data as $r => $dataRow) { + $row = $baseRow + $r; + $spreadsheet->getActiveSheet()->insertNewRowBefore($row, 1); + + $spreadsheet->getActiveSheet()->setCellValue('A' . $row, $r + 1) + ->setCellValue('B' . $row, $dataRow['title']) + ->setCellValue('C' . $row, $dataRow['price']) + ->setCellValue('D' . $row, $dataRow['quantity']) + ->setCellValue('E' . $row, '=C' . $row . '*D' . $row); +} +$spreadsheet->getActiveSheet()->removeRow($baseRow - 1, 1); + +// Save +$helper->write($spreadsheet, __FILE__); diff --git a/samples/templates/30template.xls b/samples/templates/30template.xls index af8de03b8df9a081dc61cd2aa5c4c6ad52be8b1d..58fe333da2b78ab19a5f6cc1a4450ba5e9656b55 100644 GIT binary patch delta 5286 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 delta 4123 zcmai12|QI>7vJZO?#0D5≪vB$ z$75VBcaknzRftizqlj6-AycR}Eh|R)PsL}Y) z&M0J%tJO%YkHP?j0zfw)fQzI`BmsDae(OLWK(4LbgZ!Wg!3o+DnD7|Eo*IW)5WKCc z;6H@Lm?cyqNx>u{?LUwfS&GgFu8psX8%qcffynm+KATEJr~bi{(u6-367Cs!fss?_ z3=bh!@Ft0W+>R~+lJRFu;JFcFsACw=A75pXBK=5dk;j*ifIj32Coqvbd5pqIL^qmt zjGtxEk4`uL=v0w{J2l}+C6XB2K@mjby%S@_iBpQf4jw;1QPQ@gVrIY{_yZr{0fLZJ zAV~o-5CuT_tg?!_ii)P;x;c|jfg}$ou#1m{Q6WZC!uX&HZ6>A$Eou7LEEr3hi>X5n zZ80_*4$<_mERH%|g@gvS3`wNMr8-ZlAt}zuXT)Gw7St3@Lb5_w63I5~XG;ElLBC=Bkj?*x095%@EHYg$o(LOon z z1^pLzpbU2g%d?%I20zvp-hK1Ta8!B<>Td9_6kh(!cTQ2c`e?@OLCstuiSdx!D>@g`iHCX!YB4Bd#p7QFmB2z zJV?mY-6Rrt=$`w<3^o0QBOj7V0xyW3u#5Si6Dm-}x@WLxYcbm)p(=g-{*zui17>Za z%gps`-#4Q@v-5BX8#~r;`y+K|M_5pE6 z5*_7LGUod>sFq>I0(V!=*xEl-&fueFzpvHY{KV$2!LBDUJs!-~@IJ>r>o+;aoU9TY zsSnQ`kaRhF%4f%5pAq|amPJ*(TT0Bj{0~kU%Y*OwSL!#*^4l!FKR8^dFUpjV6H#k1 z&2ec?yJSmOP5mVTrhxH&4ll>?4833FtO8SQXX4MU$5re zJ*5z8-ek-#{;s1nY<}&V_2pkp2}Padiy3|c9-1vmUJ?*=b&v3leyuG2`iel3{yE#S zo;cIhvf5YJ33SyvA2o*!slBF#kvTcN4i zHGS&Y`y#SRdY!XglnFlhoTAa&F+~= zM^*dX7p*+s-zOe#WoD(5`$yStj)&(j`Fuo6sP#_D>XgC*2cqVgYJ2k+Ms0^0YxeDW zq+4^~&rcW2zL}cG=q-(084zKizPn5C@1|Lw-6E)dfrTJTZRehRuBkO^GOV$S>->M@WAk`2!oIU82P*!WS_=;Y~2C0wtBiSm$4IWL|uF=N~{d_Vj=D!YYJ>0#q zDI_58xj=aS{;}48V(-#?UGZ-6$g4cLEiOnv%!Os8oHuq+^@8F#sEs=gB z8P`Kvjf*%kzFqqHo~19>$CPh6*)$Z_EOa|)-Ch?H-5L{}CWV1}Z&o>-?rO~p4G$_J z8OATq;JO}aq+DjZQ`tLSHdJ<3Z``C$EhBo+QhfRaMS8aZ8I& zTXacT5;d<@*VqZ<9IEWtQt0XIFL7FXsakY`!~*SYt-%k9EY$pJ6uLd$==R<+GU|+V zu6bN>ew5}XWMS8`Zbwp?cK9NgeJN(gTGK5%j;b`}?uXvJ+ojk7VbtqUdy<7>RgF`g zwd&Sgm~A!?Rkt%!(f8%;vCbNQrxA^`SZz(VNXVe={qFVrZ3DzIhc9vt&n&At)hwgD zYg0aO)8j81uLcG8*%kY%RMg|Rjr`U3Z05LX_?*wHFE}9ey4~}hWsS4_f)$xAm%99R z2_D;RpDSfkEp}SHjeXEfW00I+@}%>hwBVu_x$!R?8KFk4v2sM>pi#7kqUQCp{#qK0 zCvI1|+VbdI`NCArOMI-`=pTNs@Zh%4Zf@V@n48jhj9U|GItqybdMEb#wa=v8 zc&&H)qW{I*4GS0+4eR?UlDDEe(r3>+d)vh2qFbzUefjC(3{St$jJ8@%eDBvoZUMWl z1pMu?--fn5`eJ;s>=XWZUZ37FYcf1Xtb9c`vK{S4pU1C>s9JKSCrvqZUh8cM(Xj$E zg7MOZ*9H|e@6;dv`5PBqa9l1C*sdUwU}d-r=i#m*?E97Q}B?l)4K6K7ugs zswD&U@x*?DL-`!a)qdpgT>NK_{0k1~pK>@c zSMV2{2+H$+wxcq~NvM4|k3<0^F6=&Rh7qCa5nU361xBIk5gj%ekj4aoDj6Vy3Q~nM zDk??+9pHPmLp=aD00WIMU_bFkLX0p^Gs)PaWpEDP|IZx0|DQR0|C1bM4~0`*Fa_wJ z>PoWJN+QC>R3pJb`c2f)*~i7*{HeRBpLgLp{d4Q=jUVTu7sDr`M7 zgWQT9z!JzvSHvh#BYg#uVd)*xZWuq1K~sM|5e4mVCH@vr(@hWB1aB7A>Vlt95C<#HFsfbT9#Un;J^Heje~CZagPOIsG-_(?0! zeALYG1lZbVV^BbFfL91>>CTOw{w!@xO&yj~K#*VXW>3!$^hyCR_3`r3M^Oj>&qTu> z*J$X2p#_(=aiVuCVL})%0|8(Qs&;Kq5$203Xf0tT`rz?JCmUW?lbOhgAB^6;LST}{ Ndqjl%AEG-_^M5t_oK*k- diff --git a/samples/templates/30templatebiff5.xls b/samples/templates/30templatebiff5.xls new file mode 100644 index 0000000000000000000000000000000000000000..0523e83d451785ba550c2ded8cfaa60d9535906c GIT binary patch literal 338944 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 z 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 T;L>N{$=WmNcO3twKKuWFt;$r$ literal 0 HcmV?d00001 diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 023806d6..5656a0ff 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -2286,8 +2286,8 @@ class Xls extends BaseReader $rotation = $angle; } elseif ($angle <= 180) { $rotation = 90 - $angle; - } elseif ($angle == 255) { - $rotation = -165; + } elseif ($angle == Alignment::TEXTROTATION_STACK_EXCEL) { + $rotation = Alignment::TEXTROTATION_STACK_PHPSPREADSHEET; } $objStyle->getAlignment()->setTextRotation($rotation); @@ -2389,7 +2389,7 @@ class Xls extends BaseReader break; case 1: - $objStyle->getAlignment()->setTextRotation(-165); + $objStyle->getAlignment()->setTextRotation(Alignment::TEXTROTATION_STACK_PHPSPREADSHEET); break; case 2: diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index ee1f8aba..821aea98 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared; use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; use PhpOffice\PhpSpreadsheet\RichText\RichText; +use PhpOffice\PhpSpreadsheet\Style\Alignment; class Font { @@ -342,7 +343,7 @@ class Font // Calculate approximate rotated column width if ($rotation !== 0) { - if ($rotation == -165) { + if ($rotation == Alignment::TEXTROTATION_STACK_PHPSPREADSHEET) { // stacked text $columnWidth = 4; // approximation } else { diff --git a/src/PhpSpreadsheet/Writer/Xls/Xf.php b/src/PhpSpreadsheet/Writer/Xls/Xf.php index 3e8169b3..90d21bcf 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Xf.php +++ b/src/PhpSpreadsheet/Writer/Xls/Xf.php @@ -165,9 +165,9 @@ class Xf self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) || self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) || self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0; - $atr_pat = (($this->foregroundColor != 0x40) || - ($this->backgroundColor != 0x41) || - self::mapFillType($this->_style->getFill()->getFillType())) ? 1 : 0; + $atr_pat = ($this->foregroundColor != 0x40) ? 1 : 0; + $atr_pat = ($this->backgroundColor != 0x41) ? 1 : $atr_pat; + $atr_pat = self::mapFillType($this->_style->getFill()->getFillType()) ? 1 : $atr_pat; $atr_prot = self::mapLocked($this->_style->getProtection()->getLocked()) | self::mapHidden($this->_style->getProtection()->getHidden()); @@ -375,11 +375,7 @@ class Xf */ private static function mapBorderStyle($borderStyle) { - if (isset(self::$mapBorderStyles[$borderStyle])) { - return self::$mapBorderStyles[$borderStyle]; - } - - return 0x00; + return self::$mapBorderStyles[$borderStyle] ?? 0; } /** @@ -420,11 +416,7 @@ class Xf */ private static function mapFillType($fillType) { - if (isset(self::$mapFillTypes[$fillType])) { - return self::$mapFillTypes[$fillType]; - } - - return 0x00; + return self::$mapFillTypes[$fillType] ?? 0; } /** @@ -451,11 +443,7 @@ class Xf */ private function mapHAlign($hAlign) { - if (isset(self::$mapHAlignments[$hAlign])) { - return self::$mapHAlignments[$hAlign]; - } - - return 0; + return self::$mapHAlignments[$hAlign] ?? 0; } /** @@ -479,11 +467,7 @@ class Xf */ private static function mapVAlign($vAlign) { - if (isset(self::$mapVAlignments[$vAlign])) { - return self::$mapVAlignments[$vAlign]; - } - - return 2; + return self::$mapVAlignments[$vAlign] ?? 2; } /** @@ -497,15 +481,22 @@ class Xf { if ($textRotation >= 0) { return $textRotation; - } elseif ($textRotation == -165) { - return 255; - } elseif ($textRotation < 0) { - return 90 - $textRotation; } + if ($textRotation == Alignment::TEXTROTATION_STACK_PHPSPREADSHEET) { + return Alignment::TEXTROTATION_STACK_EXCEL; + } + + return 90 - $textRotation; } + private const LOCK_ARRAY = [ + Protection::PROTECTION_INHERIT => 1, + Protection::PROTECTION_PROTECTED => 1, + Protection::PROTECTION_UNPROTECTED => 0, + ]; + /** - * Map locked. + * Map locked values. * * @param string $locked * @@ -513,18 +504,15 @@ class Xf */ private static function mapLocked($locked) { - switch ($locked) { - case Protection::PROTECTION_INHERIT: - return 1; - case Protection::PROTECTION_PROTECTED: - return 1; - case Protection::PROTECTION_UNPROTECTED: - return 0; - default: - return 1; - } + return array_key_exists($locked, self::LOCK_ARRAY) ? self::LOCK_ARRAY[$locked] : 1; } + private const HIDDEN_ARRAY = [ + Protection::PROTECTION_INHERIT => 0, + Protection::PROTECTION_PROTECTED => 1, + Protection::PROTECTION_UNPROTECTED => 0, + ]; + /** * Map hidden. * @@ -534,15 +522,6 @@ class Xf */ private static function mapHidden($hidden) { - switch ($hidden) { - case Protection::PROTECTION_INHERIT: - return 0; - case Protection::PROTECTION_PROTECTED: - return 1; - case Protection::PROTECTION_UNPROTECTED: - return 0; - default: - return 0; - } + return array_key_exists($hidden, self::HIDDEN_ARRAY) ? self::HIDDEN_ARRAY[$hidden] : 0; } } diff --git a/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php b/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php index 56682b34..ef7d9fb4 100644 --- a/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Functional; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Style\Protection; class ActiveSheetTest extends AbstractFunctional { @@ -46,6 +47,12 @@ class ActiveSheetTest extends AbstractFunctional $spreadsheet->createSheet(2); + $spreadsheet->setActiveSheetIndex(2) + ->setCellValue('F1', 2) + ->getCell('F1') + ->getStyle() + ->getProtection() + ->setHidden(Protection::PROTECTION_PROTECTED); $spreadsheet->setActiveSheetIndex(2) ->setTitle('Test3') ->setCellValue('A1', 4) diff --git a/tests/PhpSpreadsheetTests/Shared/FontTest.php b/tests/PhpSpreadsheetTests/Shared/FontTest.php index 5eb70852..94ab74b6 100644 --- a/tests/PhpSpreadsheetTests/Shared/FontTest.php +++ b/tests/PhpSpreadsheetTests/Shared/FontTest.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Shared; use PhpOffice\PhpSpreadsheet\Shared\Font; +use PhpOffice\PhpSpreadsheet\Style\Font as StyleFont; use PHPUnit\Framework\TestCase; class FontTest extends TestCase @@ -83,4 +84,16 @@ class FontTest extends TestCase { return require 'tests/data/Shared/CentimeterSizeToPixels.php'; } + + public function testVerdanaRotation(): void + { + $font = new StyleFont(); + $font->setName('Verdana')->setSize(10); + $width = Font::getTextWidthPixelsApprox('n', $font, 0); + self::assertEquals(8, $width); + $width = Font::getTextWidthPixelsApprox('n', $font, 45); + self::assertEquals(7, $width); + $width = Font::getTextWidthPixelsApprox('n', $font, -165); + self::assertEquals(4, $width); + } } From b068639513bab86bbabc8f00a92cec23708a3ac6 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 8 Feb 2021 15:06:07 +0100 Subject: [PATCH 043/187] Substitute a literal dot inside quotes within number format masks to prevent it being mistaken for a decimal separator (#1830) * Substitute a literal dot inside quotes within number format masks to prevent it being mistaken for a decimal separator --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Style/NumberFormat.php | 10 ++++++++++ tests/data/Style/NumberFormat.php | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 181fb846..9cd09b13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fix problem resulting from literal dot inside quotes in number format masks. [PR #1830](https://github.com/PHPOffice/PhpSpreadsheet/pull/1830) - Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. [PR #1761](https://github.com/PHPOffice/PhpSpreadsheet/pull/1761) - Fix for Xlsx Chart axis titles mapping to correct X or Y axis label when only one is present. [PR #1760](https://github.com/PHPOffice/PhpSpreadsheet/pull/1760) - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index 9a0acb6f..9a2549bc 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -833,6 +833,14 @@ class NumberFormat extends Supervisor return $value; } + $format = preg_replace_callback( + '/(["])(?:(?=(\\\\?))\\2.)*?\\1/u', + function ($matches) { + return str_replace('.', chr(0x00), $matches[0]); + }, + $format + ); + // Convert any other escaped characters to quoted strings, e.g. (\T to "T") $format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/u', '"${2}"', $format); @@ -868,6 +876,8 @@ class NumberFormat extends Supervisor $value = $writerInstance->$function($value, $colors); } + $value = str_replace(chr(0x00), '.', $value); + return $value; } diff --git a/tests/data/Style/NumberFormat.php b/tests/data/Style/NumberFormat.php index 5038d6da..12aec1d3 100644 --- a/tests/data/Style/NumberFormat.php +++ b/tests/data/Style/NumberFormat.php @@ -88,6 +88,26 @@ return [ 12345.678900000001, '#,##0.000', ], + [ + '12.34 kg', + 12.34, + '0.00 "kg"', + ], + [ + 'kg 12.34', + 12.34, + '"kg" 0.00', + ], + [ + '12.34 kg.', + 12.34, + '0.00 "kg."', + ], + [ + 'kg. 12.34', + 12.34, + '"kg." 0.00', + ], [ '£ 12,345.68', 12345.678900000001, From f60f37c36290bdfd05f3e810b0cec4187b15632a Mon Sep 17 00:00:00 2001 From: Mats Sibelius Date: Mon, 8 Feb 2021 20:26:11 +0200 Subject: [PATCH 044/187] Fix case where mergeComplexNumberFormatMasks would get stuck in endless-loop (#1793) * Fix case where mergeComplexNumberFormatMasks would get stuck in endless-loop if $numbers had many decimals --- src/PhpSpreadsheet/Style/NumberFormat.php | 8 +++++--- tests/data/Style/NumberFormat.php | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index 9a2549bc..a96d2ac3 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -563,9 +563,11 @@ class NumberFormat extends Supervisor do { $tempMask = array_pop($masks); - $postDecimalMasks[] = $tempMask; - $decimalCount -= strlen($tempMask); - } while ($decimalCount > 0); + if ($tempMask !== null) { + $postDecimalMasks[] = $tempMask; + $decimalCount -= strlen($tempMask); + } + } while ($tempMask !== null && $decimalCount > 0); return [ implode('.', $masks), diff --git a/tests/data/Style/NumberFormat.php b/tests/data/Style/NumberFormat.php index 12aec1d3..81bb90ae 100644 --- a/tests/data/Style/NumberFormat.php +++ b/tests/data/Style/NumberFormat.php @@ -362,4 +362,24 @@ return [ 25, '[Green][<>25]"<>25 green";[Red]"else red"', ], + [ + 'pfx. 25.00', + 25, + '"pfx." 0.00;"pfx." -0.00;"pfx." 0.00;', + ], + [ + 'pfx. 25.20', + 25.2, + '"pfx." 0.00;"pfx." -0.00;"pfx." 0.00;', + ], + [ + 'pfx. -25.20', + -25.2, + '"pfx." 0.00;"pfx." -0.00;"pfx." 0.00;', + ], + [ + 'pfx. 25.26', + 25.255555555555555, + '"pfx." 0.00;"pfx." -0.00;"pfx." 0.00;', + ], ]; From 6f6a0586d24061eaaf1e76718f56161e9b6a8825 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Mon, 8 Feb 2021 19:39:39 +0100 Subject: [PATCH 045/187] Update change log --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cd09b13..3b8f4930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Nothing. ### Fixed - +- Fix possible endless loop in NumberFormat Masks [#1792](https://github.com/PHPOffice/PhpSpreadsheet/issues/1792) - Fix problem resulting from literal dot inside quotes in number format masks. [PR #1830](https://github.com/PHPOffice/PhpSpreadsheet/pull/1830) - Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. [PR #1761](https://github.com/PHPOffice/PhpSpreadsheet/pull/1761) - Fix for Xlsx Chart axis titles mapping to correct X or Y axis label when only one is present. [PR #1760](https://github.com/PHPOffice/PhpSpreadsheet/pull/1760) From 17f405cf62ff27f50cba22db0317305ef496de8b Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 12 Feb 2021 14:18:39 +0100 Subject: [PATCH 046/187] Attempt to provide allow failure for PHP8.1 unit tests (#1847) * Attempt to provide allow failure for PHP8.1 unit tests PHP8.1 Tests show as passed despite the errors, and it requires checking the actual output from the run to see what the rea result is; but I can live with that until github provides functionality for a proper allow_failure option --- .github/workflows/main.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5f68a4ff..707a9a3f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,12 +5,17 @@ jobs: runs-on: ubuntu-latest strategy: matrix: + experimental: + - false php-version: - '7.2' - '7.3' - '7.4' - '8.0' - - '8.1' + + include: + - php-version: '8.1' + experimental: true name: PHP ${{ matrix.php-version }} @@ -52,8 +57,10 @@ jobs: - name: Setup problem matchers for PHPUnit run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - - name: Test with PHPUnit - run: ./vendor/bin/phpunit + - name: "Run PHPUnit tests (Experimental: ${{ matrix.experimental }})" + env: + FAILURE_ACTION: "${{ matrix.experimental == true }}" + run: vendor/bin/phpunit --verbose || $FAILURE_ACTION php-cs-fixer: runs-on: ubuntu-latest From 2aa4a28863cbb9b22ee87e637f7d21ef976c00e5 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 12 Feb 2021 17:55:53 +0100 Subject: [PATCH 047/187] Move Bessel function calculations from the Engineering class to a dedicated Engineering\Bessel classes (#1846) * Move Bessel function calculations from the Engineering class to a dedicated Engineering\Bessel class Retain the original methods in the Engineering class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2 * Some refactoring of the Bessel calculation logic * Fix callable for ConvertUOM() --- .../Calculation/Calculation.php | 10 +- .../Calculation/Engineering.php | 222 ++---------------- .../Calculation/Engineering/BesselI.php | 72 ++++++ .../Calculation/Engineering/BesselJ.php | 71 ++++++ .../Calculation/Engineering/BesselK.php | 104 ++++++++ .../Calculation/Engineering/BesselY.php | 104 ++++++++ 6 files changed, 373 insertions(+), 210 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/BesselI.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/BesselK.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/BesselY.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 72aa9a51..00af49a6 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -363,22 +363,22 @@ class Calculation ], 'BESSELI' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BESSELI'], + 'functionCall' => [Engineering\BesselI::class, 'BESSELI'], 'argumentCount' => '2', ], 'BESSELJ' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BESSELJ'], + 'functionCall' => [Engineering\BesselJ::class, 'BESSELJ'], 'argumentCount' => '2', ], 'BESSELK' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BESSELK'], + 'functionCall' => [Engineering\BesselK::class, 'BESSELK'], 'argumentCount' => '2', ], 'BESSELY' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BESSELY'], + 'functionCall' => [Engineering\BesselY::class, 'BESSELY'], 'argumentCount' => '2', ], 'BETADIST' => [ @@ -594,7 +594,7 @@ class Calculation ], 'CONVERT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'CONVERTUOM'], + 'functionCall' => [Engineering\ConvertUOM::class, 'CONVERT'], 'argumentCount' => '3', ], 'CORREL' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 319a2ed6..1db4cdb1 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use Complex\Complex; use Complex\Exception as ComplexException; +use PhpOffice\PhpSpreadsheet\Calculation\Engineering\Bessel; use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM; class Engineering @@ -73,6 +74,8 @@ class Engineering * Excel Function: * BESSELI(x,ord) * + * @Deprecated 2.0.0 Use the BESSELI() method in the Engineering\BesselI class instead + * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELI returns the #VALUE! error value. * @param int $ord The order of the Bessel function. @@ -84,38 +87,7 @@ class Engineering */ public static function BESSELI($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); - - if ((is_numeric($x)) && (is_numeric($ord))) { - $ord = floor($ord); - if ($ord < 0) { - return Functions::NAN(); - } - - if (abs($x) <= 30) { - $fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord); - $ordK = 1; - $fSqrX = ($x * $x) / 4; - do { - $fTerm *= $fSqrX; - $fTerm /= ($ordK * ($ordK + $ord)); - $fResult += $fTerm; - } while ((abs($fTerm) > 1e-12) && (++$ordK < 100)); - } else { - $f_2_PI = 2 * M_PI; - - $fXAbs = abs($x); - $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs); - if (($ord & 1) && ($x < 0)) { - $fResult = -$fResult; - } - } - - return (is_nan($fResult)) ? Functions::NAN() : $fResult; - } - - return Functions::VALUE(); + return Engineering\BesselI::BESSELI($x, $ord); } /** @@ -126,6 +98,8 @@ class Engineering * Excel Function: * BESSELJ(x,ord) * + * @Deprecated 2.0.0 Use the BESSELJ() method in the Engineering\BesselJ class instead + * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELJ returns the #VALUE! error value. * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. @@ -136,76 +110,7 @@ class Engineering */ public static function BESSELJ($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); - - if ((is_numeric($x)) && (is_numeric($ord))) { - $ord = floor($ord); - if ($ord < 0) { - return Functions::NAN(); - } - - $fResult = 0; - if (abs($x) <= 30) { - $fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord); - $ordK = 1; - $fSqrX = ($x * $x) / -4; - do { - $fTerm *= $fSqrX; - $fTerm /= ($ordK * ($ordK + $ord)); - $fResult += $fTerm; - } while ((abs($fTerm) > 1e-12) && (++$ordK < 100)); - } else { - $f_PI_DIV_2 = M_PI / 2; - $f_PI_DIV_4 = M_PI / 4; - - $fXAbs = abs($x); - $fResult = sqrt(Functions::M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4); - if (($ord & 1) && ($x < 0)) { - $fResult = -$fResult; - } - } - - return (is_nan($fResult)) ? Functions::NAN() : $fResult; - } - - return Functions::VALUE(); - } - - private static function besselK0($fNum) - { - if ($fNum <= 2) { - $fNum2 = $fNum * 0.5; - $y = ($fNum2 * $fNum2); - $fRet = -log($fNum2) * self::BESSELI($fNum, 0) + - (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y * - (0.10750e-3 + $y * 0.74e-5)))))); - } else { - $y = 2 / $fNum; - $fRet = exp(-$fNum) / sqrt($fNum) * - (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y * - (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3)))))); - } - - return $fRet; - } - - private static function besselK1($fNum) - { - if ($fNum <= 2) { - $fNum2 = $fNum * 0.5; - $y = ($fNum2 * $fNum2); - $fRet = log($fNum2) * self::BESSELI($fNum, 1) + - (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y * - (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum; - } else { - $y = 2 / $fNum; - $fRet = exp(-$fNum) / sqrt($fNum) * - (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y * - (0.325614e-2 + $y * (-0.68245e-3))))))); - } - - return $fRet; + return Engineering\BesselJ::BESSELJ($x, $ord); } /** @@ -217,6 +122,8 @@ class Engineering * Excel Function: * BESSELK(x,ord) * + * @Deprecated 2.0.0 Use the BESSELK() method in the Engineering\BesselK class instead + * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELK returns the #VALUE! error value. * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. @@ -227,73 +134,7 @@ class Engineering */ public static function BESSELK($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); - - if ((is_numeric($x)) && (is_numeric($ord))) { - if (($ord < 0) || ($x == 0.0)) { - return Functions::NAN(); - } - - switch (floor($ord)) { - case 0: - $fBk = self::besselK0($x); - - break; - case 1: - $fBk = self::besselK1($x); - - break; - default: - $fTox = 2 / $x; - $fBkm = self::besselK0($x); - $fBk = self::besselK1($x); - for ($n = 1; $n < $ord; ++$n) { - $fBkp = $fBkm + $n * $fTox * $fBk; - $fBkm = $fBk; - $fBk = $fBkp; - } - } - - return (is_nan($fBk)) ? Functions::NAN() : $fBk; - } - - return Functions::VALUE(); - } - - private static function besselY0($fNum) - { - if ($fNum < 8.0) { - $y = ($fNum * $fNum); - $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733)))); - $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y)))); - $fRet = $f1 / $f2 + 0.636619772 * self::BESSELJ($fNum, 0) * log($fNum); - } else { - $z = 8.0 / $fNum; - $y = ($z * $z); - $xx = $fNum - 0.785398164; - $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6))); - $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7)))); - $fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2); - } - - return $fRet; - } - - private static function besselY1($fNum) - { - if ($fNum < 8.0) { - $y = ($fNum * $fNum); - $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y * - (-0.4237922726e7 + $y * 0.8511937935e4))))); - $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y * - (0.1020426050e6 + $y * (0.3549632885e3 + $y))))); - $fRet = $f1 / $f2 + 0.636619772 * (self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum); - } else { - $fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491); - } - - return $fRet; + return Engineering\BesselK::BESSELK($x, $ord); } /** @@ -304,48 +145,19 @@ class Engineering * Excel Function: * BESSELY(x,ord) * + * @Deprecated 2.0.0 Use the BESSELY() method in the Engineering\BesselY class instead + * * @param float $x The value at which to evaluate the function. - * If x is nonnumeric, BESSELK returns the #VALUE! error value. + * If x is nonnumeric, BESSELY returns the #VALUE! error value. * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELK returns the #VALUE! error value. - * If $ord < 0, BESSELK returns the #NUM! error value. + * If $ord is nonnumeric, BESSELY returns the #VALUE! error value. + * If $ord < 0, BESSELY returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ public static function BESSELY($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); - - if ((is_numeric($x)) && (is_numeric($ord))) { - if (($ord < 0) || ($x == 0.0)) { - return Functions::NAN(); - } - - switch (floor($ord)) { - case 0: - $fBy = self::besselY0($x); - - break; - case 1: - $fBy = self::besselY1($x); - - break; - default: - $fTox = 2 / $x; - $fBym = self::besselY0($x); - $fBy = self::besselY1($x); - for ($n = 1; $n < $ord; ++$n) { - $fByp = $n * $fTox * $fBy - $fBym; - $fBym = $fBy; - $fBy = $fByp; - } - } - - return (is_nan($fBy)) ? Functions::NAN() : $fBy; - } - - return Functions::VALUE(); + return Engineering\BesselY::BESSELY($x, $ord); } /** @@ -1882,7 +1694,7 @@ class Engineering * getConversionGroups * Returns a list of the different conversion groups for UOM conversions. * - * @Deprecated Use the getConversionCategories() method in the ConvertUOM class instead + * @Deprecated 2.0.0 Use the getConversionCategories() method in the Engineering\ConvertUOM class instead * * @return array */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php new file mode 100644 index 00000000..eda5c12b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php @@ -0,0 +1,72 @@ + 1e-12) && (++$ordK < 100)); + + return $fResult; + } + + $f_2_PI = 2 * M_PI; + + $fXAbs = abs($x); + $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs); + if (($ord & 1) && ($x < 0)) { + $fResult = -$fResult; + } + + return $fResult; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php new file mode 100644 index 00000000..62dd343a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php @@ -0,0 +1,71 @@ + 1e-12) && (++$ordK < 100)); + + return $fResult; + } + + $f_PI_DIV_2 = M_PI / 2; + $f_PI_DIV_4 = M_PI / 4; + + $fXAbs = abs($x); + $fResult = sqrt(Functions::M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4); + if (($ord & 1) && ($x < 0)) { + $fResult = -$fResult; + } + + return $fResult; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php new file mode 100644 index 00000000..f64f38b0 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php @@ -0,0 +1,104 @@ + Date: Fri, 12 Feb 2021 18:04:52 +0100 Subject: [PATCH 048/187] Update PPMT & IPMT implementation to better reflect excel behaviour. Update CUMPRINC & CUMIPMT implementation to prevent a crash while trying to add a string to a number. Update AMORLINC & AMORDEGRC to prevent crash when trying to multiply a string by a number. Update related unit tests. Update changelog to describe what we fixed. (#1840) Co-authored-by: Obmecha --- CHANGELOG.md | 11 ++++++++ src/PhpSpreadsheet/Calculation/Financial.php | 27 +++++++++++++++---- .../data/Calculation/Financial/AMORDEGRC.php | 4 +++ tests/data/Calculation/Financial/AMORLINC.php | 4 +++ tests/data/Calculation/Financial/CUMIPMT.php | 9 +++++++ tests/data/Calculation/Financial/CUMPRINC.php | 9 +++++++ tests/data/Calculation/Financial/IPMT.php | 2 +- 7 files changed, 60 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b8f4930..fe2f4ec5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,15 @@ and this project adheres to [Semantic Versioning](https://semver.org). One TextData function is also affected: `REPT()` (str_repeat). - `formatAsDate` correctly matches language metadata, reverting c55272e +- Formulae that previously crashed on sub function call returning excel error value now return said value. + The following functions are affected `CUMPRINC()`, `CUMIPMT()`, `AMORLINC()`, + `AMORDEGRC()`. + +- Adapt some function error return value to match excel's error. + The following functions are affected `PPMT()`, `IPMT()`. + +- All related unit tests have been updated to test for those modifications. + ### Deprecated - Nothing. @@ -42,6 +51,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) - Fix for not yet implemented data-types in Open Document writer [Issue #1674](https://github.com/PHPOffice/PhpSpreadsheet/issues/1674) - Fix XLSX reader when having a corrupt numeric cell data type [PR #1664](https://github.com/phpoffice/phpspreadsheet/pull/1664) +- Fix on `CUMPRINC()`, `CUMIPMT()`, `AMORLINC()`, `AMORDEGRC()` usage. When those functions called one of `YEARFRAC()`, `PPMT()`, `IPMT()` and they would get back an error +value (represented as a string), trying to use numeral operands (`+`, `/`, `-`, `*`) on said return value and a number (`float or `int`) would fail. ## 1.16.0 - 2020-12-31 diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 728167f4..7be0b594 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -253,6 +253,10 @@ class Financial $period = floor(Functions::flattenSingleValue($period)); $rate = Functions::flattenSingleValue($rate); $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); + $yearFrac = DateTime::YEARFRAC($purchased, $firstPeriod, $basis); + if (is_string($yearFrac)) { + return $yearFrac; + } // The depreciation coefficients are: // Life of assets (1/rate) Depreciation coefficient @@ -272,7 +276,7 @@ class Financial } $rate *= $amortiseCoeff; - $fNRate = round(DateTime::YEARFRAC($purchased, $firstPeriod, $basis) * $rate * $cost, 0); + $fNRate = round($yearFrac * $rate * $cost, 0); $cost -= $fNRate; $fRest = $cost - $salvage; @@ -335,6 +339,9 @@ class Financial // Note, quirky variation for leap years on the YEARFRAC for this function $purchasedYear = DateTime::YEAR($purchased); $yearFrac = DateTime::YEARFRAC($purchased, $firstPeriod, $basis); + if (is_string($yearFrac)) { + return $yearFrac; + } if (($basis == 1) && ($yearFrac < 1) && (DateTime::isLeapYear($purchasedYear))) { $yearFrac *= 365 / 366; @@ -739,7 +746,12 @@ class Financial // Calculate $interest = 0; for ($per = $start; $per <= $end; ++$per) { - $interest += self::IPMT($rate, $per, $nper, $pv, 0, $type); + $ipmt = self::IPMT($rate, $per, $nper, $pv, 0, $type); + if (is_string($ipmt)) { + return $ipmt; + } + + $interest += $ipmt; } return $interest; @@ -785,7 +797,12 @@ class Financial // Calculate $principal = 0; for ($per = $start; $per <= $end; ++$per) { - $principal += self::PPMT($rate, $per, $nper, $pv, 0, $type); + $ppmt = self::PPMT($rate, $per, $nper, $pv, 0, $type); + if (is_string($ppmt)) { + return $ppmt; + } + + $principal += $ppmt; } return $principal; @@ -1219,7 +1236,7 @@ class Financial return Functions::NAN(); } if ($per <= 0 || $per > $nper) { - return Functions::VALUE(); + return Functions::NAN(); } // Calculate @@ -1573,7 +1590,7 @@ class Financial return Functions::NAN(); } if ($per <= 0 || $per > $nper) { - return Functions::VALUE(); + return Functions::NAN(); } // Calculate diff --git a/tests/data/Calculation/Financial/AMORDEGRC.php b/tests/data/Calculation/Financial/AMORDEGRC.php index 6d75feaf..59549e78 100644 --- a/tests/data/Calculation/Financial/AMORDEGRC.php +++ b/tests/data/Calculation/Financial/AMORDEGRC.php @@ -23,4 +23,8 @@ return [ 42, 150, '2011-01-01', '2011-09-30', 20, 1, 0.4, 4, ], + [ + '#VALUE!', + 550, 'notADate', '2020-12-25', 20, 1, 0.2, 4, + ], ]; diff --git a/tests/data/Calculation/Financial/AMORLINC.php b/tests/data/Calculation/Financial/AMORLINC.php index 00ab2ae4..46f19332 100644 --- a/tests/data/Calculation/Financial/AMORLINC.php +++ b/tests/data/Calculation/Financial/AMORLINC.php @@ -23,4 +23,8 @@ return [ 0.0, 150, '2011-01-01', '2011-09-30', 20, 5, 0.20000000000000001, 4, ], + [ + '#VALUE!', + 150, 'notADate', '2011-09-30', 20, 1, 0.20000000000000001, 4, + ], ]; diff --git a/tests/data/Calculation/Financial/CUMIPMT.php b/tests/data/Calculation/Financial/CUMIPMT.php index bc14d92a..f3b27c92 100644 --- a/tests/data/Calculation/Financial/CUMIPMT.php +++ b/tests/data/Calculation/Financial/CUMIPMT.php @@ -84,4 +84,13 @@ return [ 13, 2, ], + [ + '#NUM!', + 0.0074999999999999997, + 10, + 125000, + 13, + 24, + 0, + ], ]; diff --git a/tests/data/Calculation/Financial/CUMPRINC.php b/tests/data/Calculation/Financial/CUMPRINC.php index 63392c52..0bcd8318 100644 --- a/tests/data/Calculation/Financial/CUMPRINC.php +++ b/tests/data/Calculation/Financial/CUMPRINC.php @@ -84,4 +84,13 @@ return [ 13, 2, ], + [ + '#NUM!', + 0.0074999999999999997, + 10, + 125000, + 13, + 24, + 0, + ], ]; diff --git a/tests/data/Calculation/Financial/IPMT.php b/tests/data/Calculation/Financial/IPMT.php index aaea844b..5ae1b1b4 100644 --- a/tests/data/Calculation/Financial/IPMT.php +++ b/tests/data/Calculation/Financial/IPMT.php @@ -59,7 +59,7 @@ return [ 6, ], [ - '#VALUE!', + '#NUM!', 0.0050000000000000001, 8, 2, From 6946bde47ee398b37bac685e45fe6fa87487327f Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Fri, 12 Feb 2021 18:12:19 +0100 Subject: [PATCH 049/187] Fix docblocks --- src/PhpSpreadsheet/Calculation/Financial.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 7be0b594..3c24eb3b 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -242,7 +242,7 @@ class Financial * 3 Actual/365 * 4 European 30/360 * - * @return float + * @return float|string (string containing the error type if there is an error) */ public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0) { @@ -322,7 +322,7 @@ class Financial * 3 Actual/365 * 4 European 30/360 * - * @return float + * @return float|string (string containing the error type if there is an error) */ public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0) { From 69315f06401a72dd5af92f5aab77e2505341af8e Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 12 Feb 2021 19:19:04 +0100 Subject: [PATCH 050/187] Extract all BitWise functions from the Engineering class into a dedicated BitWise class (#1848) * Extract all BitWise functions from the Engineering class into a dedicated BitWise class Retain the original methods in the Engineering class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2 Note that unit tests still point to the Engineering class stubs; these should be modified to use the bessel classes directly when the stubs are removed --- .../Calculation/Calculation.php | 10 +- .../Calculation/Engineering.php | 94 ++-------- .../Calculation/Engineering/BitWise.php | 170 ++++++++++++++++++ 3 files changed, 192 insertions(+), 82 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/BitWise.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 00af49a6..1bb73350 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -438,27 +438,27 @@ class Calculation ], 'BITAND' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BITAND'], + 'functionCall' => [Engineering\BitWise::class, 'BITAND'], 'argumentCount' => '2', ], 'BITOR' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BITOR'], + 'functionCall' => [Engineering\BitWise::class, 'BITOR'], 'argumentCount' => '2', ], 'BITXOR' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BITOR'], + 'functionCall' => [Engineering\BitWise::class, 'BITOR'], 'argumentCount' => '2', ], 'BITLSHIFT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BITLSHIFT'], + 'functionCall' => [Engineering\BitWise::class, 'BITLSHIFT'], 'argumentCount' => '2', ], 'BITRSHIFT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BITRSHIFT'], + 'functionCall' => [Engineering\BitWise::class, 'BITRSHIFT'], 'argumentCount' => '2', ], 'CEILING' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 1db4cdb1..3bf04238 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use Complex\Complex; use Complex\Exception as ComplexException; use PhpOffice\PhpSpreadsheet\Calculation\Engineering\Bessel; +use PhpOffice\PhpSpreadsheet\Calculation\Engineering\BitWise; use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM; class Engineering @@ -19,7 +20,7 @@ class Engineering * * Parses a complex number into its real and imaginary parts, and an I or J suffix * - * @deprecated 2.0.0 No longer used by internal code. Please use the Complex\Complex class instead + * @deprecated 2.0.0 No longer used by internal code. Please use the \Complex\Complex class instead * * @param string $complexNumber The complex number * @@ -1413,35 +1414,6 @@ class Engineering return self::$twoSqrtPi * $sum; } - /** - * Validate arguments passed to the bitwise functions. - * - * @param mixed $value - * - * @return int - */ - private static function validateBitwiseArgument($value) - { - $value = Functions::flattenSingleValue($value); - - if (is_int($value)) { - return $value; - } elseif (is_numeric($value)) { - if ($value == (int) ($value)) { - $value = (int) ($value); - if (($value > 2 ** 48 - 1) || ($value < 0)) { - throw new Exception(Functions::NAN()); - } - - return $value; - } - - throw new Exception(Functions::NAN()); - } - - throw new Exception(Functions::VALUE()); - } - /** * BITAND. * @@ -1450,6 +1422,8 @@ class Engineering * Excel Function: * BITAND(number1, number2) * + * @Deprecated 2.0.0 Use the BITAND() method in the Engineering\BitWise class instead + * * @param int $number1 * @param int $number2 * @@ -1457,14 +1431,7 @@ class Engineering */ public static function BITAND($number1, $number2) { - try { - $number1 = self::validateBitwiseArgument($number1); - $number2 = self::validateBitwiseArgument($number2); - } catch (Exception $e) { - return $e->getMessage(); - } - - return $number1 & $number2; + return BitWise::BITAND($number1, $number2); } /** @@ -1475,6 +1442,8 @@ class Engineering * Excel Function: * BITOR(number1, number2) * + * @Deprecated 2.0.0 Use the BITOR() method in the Engineering\BitWise class instead + * * @param int $number1 * @param int $number2 * @@ -1482,14 +1451,7 @@ class Engineering */ public static function BITOR($number1, $number2) { - try { - $number1 = self::validateBitwiseArgument($number1); - $number2 = self::validateBitwiseArgument($number2); - } catch (Exception $e) { - return $e->getMessage(); - } - - return $number1 | $number2; + return BitWise::BITOR($number1, $number2); } /** @@ -1500,6 +1462,8 @@ class Engineering * Excel Function: * BITXOR(number1, number2) * + * @Deprecated 2.0.0 Use the BITXOR() method in the Engineering\BitWise class instead + * * @param int $number1 * @param int $number2 * @@ -1507,14 +1471,7 @@ class Engineering */ public static function BITXOR($number1, $number2) { - try { - $number1 = self::validateBitwiseArgument($number1); - $number2 = self::validateBitwiseArgument($number2); - } catch (Exception $e) { - return $e->getMessage(); - } - - return $number1 ^ $number2; + return BitWise::BITXOR($number1, $number2); } /** @@ -1525,6 +1482,8 @@ class Engineering * Excel Function: * BITLSHIFT(number, shift_amount) * + * @Deprecated 2.0.0 Use the BITLSHIFT() method in the Engineering\BitWise class instead + * * @param int $number * @param int $shiftAmount * @@ -1532,20 +1491,7 @@ class Engineering */ public static function BITLSHIFT($number, $shiftAmount) { - try { - $number = self::validateBitwiseArgument($number); - } catch (Exception $e) { - return $e->getMessage(); - } - - $shiftAmount = Functions::flattenSingleValue($shiftAmount); - - $result = $number << $shiftAmount; - if ($result > 2 ** 48 - 1) { - return Functions::NAN(); - } - - return $result; + return BitWise::BITLSHIFT($number, $shiftAmount); } /** @@ -1556,6 +1502,8 @@ class Engineering * Excel Function: * BITRSHIFT(number, shift_amount) * + * @Deprecated 2.0.0 Use the BITRSHIFT() method in the Engineering\BitWise class instead + * * @param int $number * @param int $shiftAmount * @@ -1563,15 +1511,7 @@ class Engineering */ public static function BITRSHIFT($number, $shiftAmount) { - try { - $number = self::validateBitwiseArgument($number); - } catch (Exception $e) { - return $e->getMessage(); - } - - $shiftAmount = Functions::flattenSingleValue($shiftAmount); - - return $number >> $shiftAmount; + return BitWise::BITRSHIFT($number, $shiftAmount); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php b/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php new file mode 100644 index 00000000..494b5685 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php @@ -0,0 +1,170 @@ +getMessage(); + } + + return $number1 & $number2; + } + + /** + * BITOR. + * + * Returns the bitwise OR of two integer values. + * + * Excel Function: + * BITOR(number1, number2) + * + * @param int $number1 + * @param int $number2 + * + * @return int|string + */ + public static function BITOR($number1, $number2) + { + try { + $number1 = self::validateBitwiseArgument($number1); + $number2 = self::validateBitwiseArgument($number2); + } catch (Exception $e) { + return $e->getMessage(); + } + + return $number1 | $number2; + } + + /** + * BITXOR. + * + * Returns the bitwise XOR of two integer values. + * + * Excel Function: + * BITXOR(number1, number2) + * + * @param int $number1 + * @param int $number2 + * + * @return int|string + */ + public static function BITXOR($number1, $number2) + { + try { + $number1 = self::validateBitwiseArgument($number1); + $number2 = self::validateBitwiseArgument($number2); + } catch (Exception $e) { + return $e->getMessage(); + } + + return $number1 ^ $number2; + } + + /** + * BITLSHIFT. + * + * Returns the number value shifted left by shift_amount bits. + * + * Excel Function: + * BITLSHIFT(number, shift_amount) + * + * @param int $number + * @param int $shiftAmount + * + * @return int|string + */ + public static function BITLSHIFT($number, $shiftAmount) + { + try { + $number = self::validateBitwiseArgument($number); + } catch (Exception $e) { + return $e->getMessage(); + } + + $shiftAmount = Functions::flattenSingleValue($shiftAmount); + + $result = $number << $shiftAmount; + if ($result > 2 ** 48 - 1) { + return Functions::NAN(); + } + + return $result; + } + + /** + * BITRSHIFT. + * + * Returns the number value shifted right by shift_amount bits. + * + * Excel Function: + * BITRSHIFT(number, shift_amount) + * + * @param int $number + * @param int $shiftAmount + * + * @return int|string + */ + public static function BITRSHIFT($number, $shiftAmount) + { + try { + $number = self::validateBitwiseArgument($number); + } catch (Exception $e) { + return $e->getMessage(); + } + + $shiftAmount = Functions::flattenSingleValue($shiftAmount); + + return $number >> $shiftAmount; + } + + /** + * Validate arguments passed to the bitwise functions. + * + * @param mixed $value + * + * @return int + */ + private static function validateBitwiseArgument($value) + { + $value = Functions::flattenSingleValue($value); + + if (is_int($value)) { + return $value; + } elseif (is_numeric($value)) { + if ($value == (int) ($value)) { + $value = (int) ($value); + if (($value > 2 ** 48 - 1) || ($value < 0)) { + throw new Exception(Functions::NAN()); + } + + return $value; + } + + throw new Exception(Functions::NAN()); + } + + throw new Exception(Functions::VALUE()); + } +} From 61d2e6dcd347ebc1f51de34dfd97db6499e1f8e5 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 13 Feb 2021 11:21:16 +0100 Subject: [PATCH 051/187] Extract all Base Conversion functions from the Engineering class into dedicated Base Conversion classes (#1849) * Extract all Base Conversion functions from the Engineering class into a dedicated Convert classes extending from a common ConvertBase class Retain the original methods in the Engineering class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2 Note that unit tests still point to the Engineering class stubs; these should be modified to use the Convert classes directly when the stubs are removed * Split out into separate base conversion classes, with a ConvertBase class for common methods --- .../Calculation/Calculation.php | 24 +- .../Calculation/Engineering.php | 333 +++--------------- .../Calculation/Engineering/ConvertBase.php | 63 ++++ .../Calculation/Engineering/ConvertBinary.php | 132 +++++++ .../Engineering/ConvertDecimal.php | 158 +++++++++ .../Calculation/Engineering/ConvertHex.php | 147 ++++++++ .../Calculation/Engineering/ConvertOctal.php | 143 ++++++++ 7 files changed, 696 insertions(+), 304 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 1bb73350..4c7d7b79 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -403,17 +403,17 @@ class Calculation ], 'BIN2DEC' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BINTODEC'], + 'functionCall' => [Engineering\ConvertBinary::class, 'toDecimal'], 'argumentCount' => '1', ], 'BIN2HEX' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BINTOHEX'], + 'functionCall' => [Engineering\ConvertBinary::class, 'toHex'], 'argumentCount' => '1,2', ], 'BIN2OCT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'BINTOOCT'], + 'functionCall' => [Engineering\ConvertBinary::class, 'toOctal'], 'argumentCount' => '1,2', ], 'BINOMDIST' => [ @@ -814,17 +814,17 @@ class Calculation ], 'DEC2BIN' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'DECTOBIN'], + 'functionCall' => [Engineering\ConvertDecimal::class, 'toBinary'], 'argumentCount' => '1,2', ], 'DEC2HEX' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'DECTOHEX'], + 'functionCall' => [Engineering\ConvertDecimal::class, 'toHex'], 'argumentCount' => '1,2', ], 'DEC2OCT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'DECTOOCT'], + 'functionCall' => [Engineering\ConvertDecimal::class, 'toOctal'], 'argumentCount' => '1,2', ], 'DECIMAL' => [ @@ -1216,17 +1216,17 @@ class Calculation ], 'HEX2BIN' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'HEXTOBIN'], + 'functionCall' => [Engineering\ConvertHex::class, 'toBinary'], 'argumentCount' => '1,2', ], 'HEX2DEC' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'HEXTODEC'], + 'functionCall' => [Engineering\ConvertHex::class, 'toDecimal'], 'argumentCount' => '1', ], 'HEX2OCT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'HEXTOOCT'], + 'functionCall' => [Engineering\ConvertHex::class, 'toOctal'], 'argumentCount' => '1,2', ], 'HLOOKUP' => [ @@ -1840,17 +1840,17 @@ class Calculation ], 'OCT2BIN' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'OCTTOBIN'], + 'functionCall' => [Engineering\ConvertOctal::class, 'toBinary'], 'argumentCount' => '1,2', ], 'OCT2DEC' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'OCTTODEC'], + 'functionCall' => [Engineering\ConvertOctal::class, 'toDecimal'], 'argumentCount' => '1', ], 'OCT2HEX' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'OCTTOHEX'], + 'functionCall' => [Engineering\ConvertOctal::class, 'toHex'], 'argumentCount' => '1,2', ], 'ODD' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 3bf04238..1429c7a9 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -4,9 +4,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use Complex\Complex; use Complex\Exception as ComplexException; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering\Bessel; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering\BitWise; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM; class Engineering { @@ -37,35 +34,6 @@ class Engineering ]; } - /** - * Formats a number base string value with leading zeroes. - * - * @param string $xVal The "number" to pad - * @param int $places The length that we want to pad this value - * - * @return string The padded "number" - */ - private static function nbrConversionFormat($xVal, $places) - { - if ($places !== null) { - if (is_numeric($places)) { - $places = (int) $places; - } else { - return Functions::VALUE(); - } - if ($places < 0) { - return Functions::NAN(); - } - if (strlen($xVal) <= $places) { - return substr(str_pad($xVal, $places, '0', STR_PAD_LEFT), -10); - } - - return Functions::NAN(); - } - - return substr($xVal, -10); - } - /** * BESSELI. * @@ -169,6 +137,8 @@ class Engineering * Excel Function: * BIN2DEC(x) * + * @Deprecated 2.0.0 Use the toDecimal() method in the Engineering\ConvertBinary class instead + * * @param string $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant * bit of number is the sign bit. The remaining 9 bits are magnitude bits. @@ -180,32 +150,7 @@ class Engineering */ public static function BINTODEC($x) { - $x = Functions::flattenSingleValue($x); - - if (is_bool($x)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return Functions::VALUE(); - } - } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $x = floor((float) $x); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[01]/', $x, $out)) { - return Functions::NAN(); - } - if (strlen($x) > 10) { - return Functions::NAN(); - } elseif (strlen($x) == 10) { - // Two's Complement - $x = substr($x, -9); - - return '-' . (512 - bindec($x)); - } - - return bindec($x); + return Engineering\ConvertBinary::toDecimal($x); } /** @@ -216,6 +161,8 @@ class Engineering * Excel Function: * BIN2HEX(x[,places]) * + * @Deprecated 2.0.0 Use the toHex() method in the Engineering\ConvertBinary class instead + * * @param string $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant * bit of number is the sign bit. The remaining 9 bits are magnitude bits. @@ -233,33 +180,7 @@ class Engineering */ public static function BINTOHEX($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - // Argument X - if (is_bool($x)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return Functions::VALUE(); - } - } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $x = floor((float) $x); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[01]/', $x, $out)) { - return Functions::NAN(); - } - if (strlen($x) > 10) { - return Functions::NAN(); - } elseif (strlen($x) == 10) { - // Two's Complement - return str_repeat('F', 8) . substr(strtoupper(dechex((int) bindec(substr($x, -9)))), -2); - } - $hexVal = (string) strtoupper(dechex((int) bindec($x))); - - return self::nbrConversionFormat($hexVal, $places); + return Engineering\ConvertBinary::toHex($x, $places); } /** @@ -270,6 +191,8 @@ class Engineering * Excel Function: * BIN2OCT(x[,places]) * + * @Deprecated 2.0.0 Use the toOctal() method in the Engineering\ConvertBinary class instead + * * @param string $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant * bit of number is the sign bit. The remaining 9 bits are magnitude bits. @@ -287,32 +210,7 @@ class Engineering */ public static function BINTOOCT($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return Functions::VALUE(); - } - } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $x = floor((float) $x); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[01]/', $x, $out)) { - return Functions::NAN(); - } - if (strlen($x) > 10) { - return Functions::NAN(); - } elseif (strlen($x) == 10) { - // Two's Complement - return str_repeat('7', 7) . substr(strtoupper(decoct((int) bindec(substr($x, -9)))), -3); - } - $octVal = (string) decoct((int) bindec($x)); - - return self::nbrConversionFormat($octVal, $places); + return Engineering\ConvertBinary::toOctal($x, $places); } /** @@ -323,6 +221,8 @@ class Engineering * Excel Function: * DEC2BIN(x[,places]) * + * @Deprecated 2.0.0 Use the toBinary() method in the Engineering\ConvertDecimal class instead + * * @param string $x The decimal integer you want to convert. If number is negative, * valid place values are ignored and DEC2BIN returns a 10-character * (10-bit) binary number in which the most significant bit is the sign @@ -344,34 +244,7 @@ class Engineering */ public static function DECTOBIN($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return Functions::VALUE(); - } - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) { - return Functions::VALUE(); - } - - $x = (int) floor((float) $x); - if ($x < -512 || $x > 511) { - return Functions::NAN(); - } - - $r = decbin($x); - // Two's Complement - $r = substr($r, -10); - if (strlen($r) >= 11) { - return Functions::NAN(); - } - - return self::nbrConversionFormat($r, $places); + return Engineering\ConvertDecimal::toBinary($x, $places); } /** @@ -382,6 +255,8 @@ class Engineering * Excel Function: * DEC2HEX(x[,places]) * + * @Deprecated 2.0.0 Use the toHex() method in the Engineering\ConvertDecimal class instead + * * @param string $x The decimal integer you want to convert. If number is negative, * places is ignored and DEC2HEX returns a 10-character (40-bit) * hexadecimal number in which the most significant bit is the sign @@ -403,28 +278,7 @@ class Engineering */ public static function DECTOHEX($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return Functions::VALUE(); - } - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) { - return Functions::VALUE(); - } - $x = (int) floor((float) $x); - $r = strtoupper(dechex($x)); - if (strlen($r) == 8) { - // Two's Complement - $r = 'FF' . $r; - } - - return self::nbrConversionFormat($r, $places); + return Engineering\ConvertDecimal::toHex($x, $places); } /** @@ -435,6 +289,8 @@ class Engineering * Excel Function: * DEC2OCT(x[,places]) * + * @Deprecated 2.0.0 Use the toOctal() method in the Engineering\ConvertDecimal class instead + * * @param string $x The decimal integer you want to convert. If number is negative, * places is ignored and DEC2OCT returns a 10-character (30-bit) * octal number in which the most significant bit is the sign bit. @@ -456,29 +312,7 @@ class Engineering */ public static function DECTOOCT($x, $places = null) { - $xorig = $x; - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $x = (int) $x; - } else { - return Functions::VALUE(); - } - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[-0123456789.]/', $x, $out)) { - return Functions::VALUE(); - } - $x = (int) floor((float) $x); - $r = decoct($x); - if (strlen($r) == 11) { - // Two's Complement - $r = substr($r, -10); - } - - return self::nbrConversionFormat($r, $places); + return Engineering\ConvertDecimal::toOctal($x, $places); } /** @@ -489,6 +323,8 @@ class Engineering * Excel Function: * HEX2BIN(x[,places]) * + * @Deprecated 2.0.0 Use the toBinary() method in the Engineering\ConvertHex class instead + * * @param string $x the hexadecimal number you want to convert. * Number cannot contain more than 10 characters. * The most significant bit of number is the sign bit (40th bit from the right). @@ -510,18 +346,7 @@ class Engineering */ public static function HEXTOBIN($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - return Functions::VALUE(); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) { - return Functions::NAN(); - } - - return self::DECTOBIN(self::HEXTODEC($x), $places); + return Engineering\ConvertHex::toBinary($x, $places); } /** @@ -532,6 +357,8 @@ class Engineering * Excel Function: * HEX2DEC(x) * + * @Deprecated 2.0.0 Use the toDecimal() method in the Engineering\ConvertHex class instead + * * @param string $x The hexadecimal number you want to convert. This number cannot * contain more than 10 characters (40 bits). The most significant * bit of number is the sign bit. The remaining 39 bits are magnitude @@ -544,33 +371,7 @@ class Engineering */ public static function HEXTODEC($x) { - $x = Functions::flattenSingleValue($x); - - if (is_bool($x)) { - return Functions::VALUE(); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) { - return Functions::NAN(); - } - - if (strlen($x) > 10) { - return Functions::NAN(); - } - - $binX = ''; - foreach (str_split($x) as $char) { - $binX .= str_pad(base_convert($char, 16, 2), 4, '0', STR_PAD_LEFT); - } - if (strlen($binX) == 40 && $binX[0] == '1') { - for ($i = 0; $i < 40; ++$i) { - $binX[$i] = ($binX[$i] == '1' ? '0' : '1'); - } - - return (bindec($binX) + 1) * -1; - } - - return bindec($binX); + return Engineering\ConvertHex::toDecimal($x); } /** @@ -581,6 +382,8 @@ class Engineering * Excel Function: * HEX2OCT(x[,places]) * + * @Deprecated 2.0.0 Use the toOctal() method in the Engineering\ConvertHex class instead + * * @param string $x The hexadecimal number you want to convert. Number cannot * contain more than 10 characters. The most significant bit of * number is the sign bit. The remaining 39 bits are magnitude @@ -606,23 +409,7 @@ class Engineering */ public static function HEXTOOCT($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - return Functions::VALUE(); - } - $x = (string) $x; - if (strlen($x) > preg_match_all('/[0123456789ABCDEF]/', strtoupper($x), $out)) { - return Functions::NAN(); - } - - $decimal = self::HEXTODEC($x); - if ($decimal < -536870912 || $decimal > 536870911) { - return Functions::NAN(); - } - - return self::DECTOOCT($decimal, $places); + return Engineering\ConvertHex::toOctal($x, $places); } /** @@ -633,6 +420,8 @@ class Engineering * Excel Function: * OCT2BIN(x[,places]) * + * @Deprecated 2.0.0 Use the toBinary() method in the Engineering\ConvertOctal class instead + * * @param string $x The octal number you want to convert. Number may not * contain more than 10 characters. The most significant * bit of number is the sign bit. The remaining 29 bits @@ -660,18 +449,7 @@ class Engineering */ public static function OCTTOBIN($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - return Functions::VALUE(); - } - $x = (string) $x; - if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) { - return Functions::NAN(); - } - - return self::DECTOBIN(self::OCTTODEC($x), $places); + return Engineering\ConvertOctal::toBinary($x, $places); } /** @@ -682,6 +460,8 @@ class Engineering * Excel Function: * OCT2DEC(x) * + * @Deprecated 2.0.0 Use the toDecimal() method in the Engineering\ConvertOctal class instead + * * @param string $x The octal number you want to convert. Number may not contain * more than 10 octal characters (30 bits). The most significant * bit of number is the sign bit. The remaining 29 bits are @@ -694,28 +474,7 @@ class Engineering */ public static function OCTTODEC($x) { - $x = Functions::flattenSingleValue($x); - - if (is_bool($x)) { - return Functions::VALUE(); - } - $x = (string) $x; - if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) { - return Functions::NAN(); - } - $binX = ''; - foreach (str_split($x) as $char) { - $binX .= str_pad(decbin((int) $char), 3, '0', STR_PAD_LEFT); - } - if (strlen($binX) == 30 && $binX[0] == '1') { - for ($i = 0; $i < 30; ++$i) { - $binX[$i] = ($binX[$i] == '1' ? '0' : '1'); - } - - return (bindec($binX) + 1) * -1; - } - - return bindec($binX); + return Engineering\ConvertOctal::toDecimal($x); } /** @@ -726,6 +485,8 @@ class Engineering * Excel Function: * OCT2HEX(x[,places]) * + * @Deprecated 2.0.0 Use the toHex() method in the Engineering\ConvertOctal class instead + * * @param string $x The octal number you want to convert. Number may not contain * more than 10 octal characters (30 bits). The most significant * bit of number is the sign bit. The remaining 29 bits are @@ -748,19 +509,7 @@ class Engineering */ public static function OCTTOHEX($x, $places = null) { - $x = Functions::flattenSingleValue($x); - $places = Functions::flattenSingleValue($places); - - if (is_bool($x)) { - return Functions::VALUE(); - } - $x = (string) $x; - if (preg_match_all('/[01234567]/', $x, $out) != strlen($x)) { - return Functions::NAN(); - } - $hexVal = strtoupper(dechex((int) self::OCTTODEC((int) $x))); - - return self::nbrConversionFormat($hexVal, $places); + return Engineering\ConvertOctal::toHex($x, $places); } /** @@ -1431,7 +1180,7 @@ class Engineering */ public static function BITAND($number1, $number2) { - return BitWise::BITAND($number1, $number2); + return Engineering\BitWise::BITAND($number1, $number2); } /** @@ -1451,7 +1200,7 @@ class Engineering */ public static function BITOR($number1, $number2) { - return BitWise::BITOR($number1, $number2); + return Engineering\BitWise::BITOR($number1, $number2); } /** @@ -1471,7 +1220,7 @@ class Engineering */ public static function BITXOR($number1, $number2) { - return BitWise::BITXOR($number1, $number2); + return Engineering\BitWise::BITXOR($number1, $number2); } /** @@ -1491,7 +1240,7 @@ class Engineering */ public static function BITLSHIFT($number, $shiftAmount) { - return BitWise::BITLSHIFT($number, $shiftAmount); + return Engineering\BitWise::BITLSHIFT($number, $shiftAmount); } /** @@ -1511,7 +1260,7 @@ class Engineering */ public static function BITRSHIFT($number, $shiftAmount) { - return BitWise::BITRSHIFT($number, $shiftAmount); + return Engineering\BitWise::BITRSHIFT($number, $shiftAmount); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php new file mode 100644 index 00000000..5122e011 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php @@ -0,0 +1,63 @@ +getMessage(); + } + + if (strlen($value) == 10) { + // Two's Complement + $value = substr($value, -9); + + return '-' . (512 - bindec($value)); + } + + return bindec($value); + } + + /** + * toHex. + * + * Return a binary value as hex. + * + * Excel Function: + * BIN2HEX(x[,places]) + * + * @param string $value The binary number (as a string) that you want to convert. The number + * cannot contain more than 10 characters (10 bits). The most significant + * bit of number is the sign bit. The remaining 9 bits are magnitude bits. + * Negative numbers are represented using two's-complement notation. + * If number is not a valid binary number, or if number contains more than + * 10 characters (10 bits), BIN2HEX returns the #NUM! error value. + * @param int $places The number of characters to use. If places is omitted, BIN2HEX uses the + * minimum number of characters necessary. Places is useful for padding the + * return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, BIN2HEX returns the #VALUE! error value. + * If places is negative, BIN2HEX returns the #NUM! error value. + */ + public static function toHex($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value), true); + $value = self::validateBinary($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (strlen($value) == 10) { + // Two's Complement + return str_repeat('F', 8) . substr(strtoupper(dechex((int) bindec(substr($value, -9)))), -2); + } + $hexVal = (string) strtoupper(dechex((int) bindec($value))); + + return self::nbrConversionFormat($hexVal, $places); + } + + /** + * toOctal. + * + * Return a binary value as octal. + * + * Excel Function: + * BIN2OCT(x[,places]) + * + * @param string $value The binary number (as a string) that you want to convert. The number + * cannot contain more than 10 characters (10 bits). The most significant + * bit of number is the sign bit. The remaining 9 bits are magnitude bits. + * Negative numbers are represented using two's-complement notation. + * If number is not a valid binary number, or if number contains more than + * 10 characters (10 bits), BIN2OCT returns the #NUM! error value. + * @param int $places The number of characters to use. If places is omitted, BIN2OCT uses the + * minimum number of characters necessary. Places is useful for padding the + * return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, BIN2OCT returns the #VALUE! error value. + * If places is negative, BIN2OCT returns the #NUM! error value. + */ + public static function toOctal($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value), true); + $value = self::validateBinary($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (strlen($value) == 10) { + // Two's Complement + return str_repeat('7', 7) . substr(strtoupper(decoct((int) bindec(substr($value, -9)))), -3); + } + $octVal = (string) decoct((int) bindec($value)); + + return self::nbrConversionFormat($octVal, $places); + } + + protected static function validateBinary(string $value): string + { + if ((strlen($value) > preg_match_all('/[01]/', $value)) || (strlen($value) > 10)) { + throw new Exception(Functions::NAN()); + } + + return $value; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php new file mode 100644 index 00000000..bd249633 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php @@ -0,0 +1,158 @@ + 511, DEC2BIN returns the #NUM! error + * value. + * If number is nonnumeric, DEC2BIN returns the #VALUE! error value. + * If DEC2BIN requires more than places characters, it returns the #NUM! + * error value. + * @param int $places The number of characters to use. If places is omitted, DEC2BIN uses + * the minimum number of characters necessary. Places is useful for + * padding the return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, DEC2BIN returns the #VALUE! error value. + * If places is zero or negative, DEC2BIN returns the #NUM! error value. + */ + public static function toBinary($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateDecimal($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + $value = (int) floor((float) $value); + if ($value < -512 || $value > 511) { + return Functions::NAN(); + } + + $r = decbin($value); + // Two's Complement + $r = substr($r, -10); + if (strlen($r) >= 11) { + return Functions::NAN(); + } + + return self::nbrConversionFormat($r, $places); + } + + /** + * toHex. + * + * Return a decimal value as hex. + * + * Excel Function: + * DEC2HEX(x[,places]) + * + * @param string $value The decimal integer you want to convert. If number is negative, + * places is ignored and DEC2HEX returns a 10-character (40-bit) + * hexadecimal number in which the most significant bit is the sign + * bit. The remaining 39 bits are magnitude bits. Negative numbers + * are represented using two's-complement notation. + * If number < -549,755,813,888 or if number > 549,755,813,887, + * DEC2HEX returns the #NUM! error value. + * If number is nonnumeric, DEC2HEX returns the #VALUE! error value. + * If DEC2HEX requires more than places characters, it returns the + * #NUM! error value. + * @param int $places The number of characters to use. If places is omitted, DEC2HEX uses + * the minimum number of characters necessary. Places is useful for + * padding the return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, DEC2HEX returns the #VALUE! error value. + * If places is zero or negative, DEC2HEX returns the #NUM! error value. + */ + public static function toHex($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateDecimal($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + $value = (int) floor((float) $value); + $r = strtoupper(dechex($value)); + if (strlen($r) == 8) { + // Two's Complement + $r = 'FF' . $r; + } + + return self::nbrConversionFormat($r, $places); + } + + /** + * toOctal. + * + * Return an decimal value as octal. + * + * Excel Function: + * DEC2OCT(x[,places]) + * + * @param string $value The decimal integer you want to convert. If number is negative, + * places is ignored and DEC2OCT returns a 10-character (30-bit) + * octal number in which the most significant bit is the sign bit. + * The remaining 29 bits are magnitude bits. Negative numbers are + * represented using two's-complement notation. + * If number < -536,870,912 or if number > 536,870,911, DEC2OCT + * returns the #NUM! error value. + * If number is nonnumeric, DEC2OCT returns the #VALUE! error value. + * If DEC2OCT requires more than places characters, it returns the + * #NUM! error value. + * @param int $places The number of characters to use. If places is omitted, DEC2OCT uses + * the minimum number of characters necessary. Places is useful for + * padding the return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, DEC2OCT returns the #VALUE! error value. + * If places is zero or negative, DEC2OCT returns the #NUM! error value. + */ + public static function toOctal($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateDecimal($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + $value = (int) floor((float) $value); + $r = decoct($value); + if (strlen($r) == 11) { + // Two's Complement + $r = substr($r, -10); + } + + return self::nbrConversionFormat($r, $places); + } + + protected static function validateDecimal(string $value): string + { + if (strlen($value) > preg_match_all('/[-0123456789.]/', $value)) { + throw new Exception(Functions::VALUE()); + } + + return $value; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php new file mode 100644 index 00000000..9147bf08 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php @@ -0,0 +1,147 @@ +getMessage(); + } + + return ConvertDecimal::toBinary(self::toDecimal($value), $places); + } + + /** + * toDecimal. + * + * Return a hex value as decimal. + * + * Excel Function: + * HEX2DEC(x) + * + * @param string $value The hexadecimal number you want to convert. This number cannot + * contain more than 10 characters (40 bits). The most significant + * bit of number is the sign bit. The remaining 39 bits are magnitude + * bits. Negative numbers are represented using two's-complement + * notation. + * If number is not a valid hexadecimal number, HEX2DEC returns the + * #NUM! error value. + */ + public static function toDecimal($value): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateHex($value); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (strlen($value) > 10) { + return Functions::NAN(); + } + + $binX = ''; + foreach (str_split($value) as $char) { + $binX .= str_pad(base_convert($char, 16, 2), 4, '0', STR_PAD_LEFT); + } + if (strlen($binX) == 40 && $binX[0] == '1') { + for ($i = 0; $i < 40; ++$i) { + $binX[$i] = ($binX[$i] == '1' ? '0' : '1'); + } + + return (bindec($binX) + 1) * -1; + } + + return bindec($binX); + } + + /** + * toOctal. + * + * Return a hex value as octal. + * + * Excel Function: + * HEX2OCT(x[,places]) + * + * @param string $value The hexadecimal number you want to convert. Number cannot + * contain more than 10 characters. The most significant bit of + * number is the sign bit. The remaining 39 bits are magnitude + * bits. Negative numbers are represented using two's-complement + * notation. + * If number is negative, HEX2OCT ignores places and returns a + * 10-character octal number. + * If number is negative, it cannot be less than FFE0000000, and + * if number is positive, it cannot be greater than 1FFFFFFF. + * If number is not a valid hexadecimal number, HEX2OCT returns + * the #NUM! error value. + * If HEX2OCT requires more than places characters, it returns + * the #NUM! error value. + * @param int $places The number of characters to use. If places is omitted, HEX2OCT + * uses the minimum number of characters necessary. Places is + * useful for padding the return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, HEX2OCT returns the #VALUE! error + * value. + * If places is negative, HEX2OCT returns the #NUM! error value. + */ + public static function toOctal($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateHex($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + $decimal = self::toDecimal($value); + if ($decimal < -536870912 || $decimal > 536870911) { + return Functions::NAN(); + } + + return ConvertDecimal::toOctal($decimal, $places); + } + + protected static function validateHex(string $value): string + { + if (strlen($value) > preg_match_all('/[0123456789ABCDEF]/', $value)) { + throw new Exception(Functions::NAN()); + } + + return $value; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php new file mode 100644 index 00000000..1e8823ad --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php @@ -0,0 +1,143 @@ +getMessage(); + } + + return ConvertDecimal::toBinary(self::toDecimal($value), $places); + } + + /** + * toDecimal. + * + * Return an octal value as decimal. + * + * Excel Function: + * OCT2DEC(x) + * + * @param string $value The octal number you want to convert. Number may not contain + * more than 10 octal characters (30 bits). The most significant + * bit of number is the sign bit. The remaining 29 bits are + * magnitude bits. Negative numbers are represented using + * two's-complement notation. + * If number is not a valid octal number, OCT2DEC returns the + * #NUM! error value. + */ + public static function toDecimal($value): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateOctal($value); + } catch (Exception $e) { + return $e->getMessage(); + } + + $binX = ''; + foreach (str_split($value) as $char) { + $binX .= str_pad(decbin((int) $char), 3, '0', STR_PAD_LEFT); + } + if (strlen($binX) == 30 && $binX[0] == '1') { + for ($i = 0; $i < 30; ++$i) { + $binX[$i] = ($binX[$i] == '1' ? '0' : '1'); + } + + return (bindec($binX) + 1) * -1; + } + + return bindec($binX); + } + + /** + * toHex. + * + * Return an octal value as hex. + * + * Excel Function: + * OCT2HEX(x[,places]) + * + * @param string $value The octal number you want to convert. Number may not contain + * more than 10 octal characters (30 bits). The most significant + * bit of number is the sign bit. The remaining 29 bits are + * magnitude bits. Negative numbers are represented using + * two's-complement notation. + * If number is negative, OCT2HEX ignores places and returns a + * 10-character hexadecimal number. + * If number is not a valid octal number, OCT2HEX returns the + * #NUM! error value. + * If OCT2HEX requires more than places characters, it returns + * the #NUM! error value. + * @param int $places The number of characters to use. If places is omitted, OCT2HEX + * uses the minimum number of characters necessary. Places is useful + * for padding the return value with leading 0s (zeros). + * If places is not an integer, it is truncated. + * If places is nonnumeric, OCT2HEX returns the #VALUE! error value. + * If places is negative, OCT2HEX returns the #NUM! error value. + */ + public static function toHex($value, $places = null): string + { + try { + $value = self::validateValue(Functions::flattenSingleValue($value)); + $value = self::validateOctal($value); + $places = self::validatePlaces(Functions::flattenSingleValue($places)); + } catch (Exception $e) { + return $e->getMessage(); + } + + $hexVal = strtoupper(dechex((int) self::toDecimal((int) $value))); + + return self::nbrConversionFormat($hexVal, $places); + } + + protected static function validateOctal(string $value): string + { + if (strlen($value) > preg_match_all('/[01234567]/', $value)) { + throw new Exception(Functions::NAN()); + } + + return $value; + } +} From be328c33a53be9d5ddf8aafa6678b02dc3687df4 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 13 Feb 2021 12:55:41 +0100 Subject: [PATCH 052/187] Extract all Error functions from the Engineering class into a dedicated Erf and ErfC classes (#1850) * Extract all Error functions from the Engineering class into a dedicated Erf and ErfC classes Retain the original methods in the Engineering class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2 Note that unit tests still point to the Engineering class stubs; these should be modified to use the Erf and ErfC classes directly when the stubs are removed * Reminder that ERF is used (either directly or Indirectly) in some of the statistical functions as well --- .../Calculation/Calculation.php | 6 +- .../Calculation/Engineering.php | 93 ++----------------- .../Calculation/Engineering/Erf.php | 91 ++++++++++++++++++ .../Calculation/Engineering/ErfC.php | 68 ++++++++++++++ .../Calculation/Statistical.php | 2 +- 5 files changed, 172 insertions(+), 88 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/Erf.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ErfC.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 4c7d7b79..537b9372 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -939,17 +939,17 @@ class Calculation ], 'ERF' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'ERF'], + 'functionCall' => [Engineering\Erf::class, 'ERF'], 'argumentCount' => '1,2', ], 'ERF.PRECISE' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'ERFPRECISE'], + 'functionCall' => [Engineering\Erf::class, 'ERFPRECISE'], 'argumentCount' => '1', ], 'ERFC' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'ERFC'], + 'functionCall' => [Engineering\ErfC::class, 'ERFC'], 'argumentCount' => '1', ], 'ERFC.PRECISE' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 1429c7a9..92b68807 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -1135,34 +1135,6 @@ class Engineering return (int) ($number >= $step); } - // - // Private method to calculate the erf value - // - private static $twoSqrtPi = 1.128379167095512574; - - public static function erfVal($x) - { - if (abs($x) > 2.2) { - return 1 - self::erfcVal($x); - } - $sum = $term = $x; - $xsqr = ($x * $x); - $j = 1; - do { - $term *= $xsqr / $j; - $sum -= $term / (2 * $j + 1); - ++$j; - $term *= $xsqr / $j; - $sum += $term / (2 * $j + 1); - ++$j; - if ($sum == 0.0) { - break; - } - } while (abs($term / $sum) > Functions::PRECISION); - - return self::$twoSqrtPi * $sum; - } - /** * BITAND. * @@ -1276,6 +1248,8 @@ class Engineering * Excel Function: * ERF(lower[,upper]) * + * @Deprecated 2.0.0 Use the ERF() method in the Engineering\Erf class instead + * * @param float $lower lower bound for integrating ERF * @param float $upper upper bound for integrating ERF. * If omitted, ERF integrates between zero and lower_limit @@ -1284,19 +1258,7 @@ class Engineering */ public static function ERF($lower, $upper = null) { - $lower = Functions::flattenSingleValue($lower); - $upper = Functions::flattenSingleValue($upper); - - if (is_numeric($lower)) { - if ($upper === null) { - return self::erfVal($lower); - } - if (is_numeric($upper)) { - return self::erfVal($upper) - self::erfVal($lower); - } - } - - return Functions::VALUE(); + return Engineering\Erf::ERF($lower, $upper); } /** @@ -1307,48 +1269,15 @@ class Engineering * Excel Function: * ERF.PRECISE(limit) * + * @Deprecated 2.0.0 Use the ERFPRECISE() method in the Engineering\Erf class instead + * * @param float $limit bound for integrating ERF * * @return float|string */ public static function ERFPRECISE($limit) { - $limit = Functions::flattenSingleValue($limit); - - return self::ERF($limit); - } - - // - // Private method to calculate the erfc value - // - private static $oneSqrtPi = 0.564189583547756287; - - private static function erfcVal($x) - { - if (abs($x) < 2.2) { - return 1 - self::erfVal($x); - } - if ($x < 0) { - return 2 - self::ERFC(-$x); - } - $a = $n = 1; - $b = $c = $x; - $d = ($x * $x) + 0.5; - $q1 = $q2 = $b / $d; - $t = 0; - do { - $t = $a * $n + $b * $x; - $a = $b; - $b = $t; - $t = $c * $n + $d * $x; - $c = $d; - $d = $t; - $n += 0.5; - $q1 = $q2; - $q2 = $b / $d; - } while ((abs($q1 - $q2) / $q2) > Functions::PRECISION); - - return self::$oneSqrtPi * exp(-$x * $x) * $q2; + return Engineering\Erf::ERFPRECISE($limit); } /** @@ -1364,19 +1293,15 @@ class Engineering * Excel Function: * ERFC(x) * + * @Deprecated 2.0.0 Use the ERFC() method in the Engineering\ErfC class instead + * * @param float $x The lower bound for integrating ERFC * * @return float|string */ public static function ERFC($x) { - $x = Functions::flattenSingleValue($x); - - if (is_numeric($x)) { - return self::erfcVal($x); - } - - return Functions::VALUE(); + return Engineering\ErfC::ERFC($x); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Erf.php b/src/PhpSpreadsheet/Calculation/Engineering/Erf.php new file mode 100644 index 00000000..54358ebd --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/Erf.php @@ -0,0 +1,91 @@ + 2.2) { + return 1 - ErfC::ERFC($value); + } + $sum = $term = $value; + $xsqr = ($value * $value); + $j = 1; + do { + $term *= $xsqr / $j; + $sum -= $term / (2 * $j + 1); + ++$j; + $term *= $xsqr / $j; + $sum += $term / (2 * $j + 1); + ++$j; + if ($sum == 0.0) { + break; + } + } while (abs($term / $sum) > Functions::PRECISION); + + return self::$twoSqrtPi * $sum; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php b/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php new file mode 100644 index 00000000..31c3bd75 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php @@ -0,0 +1,68 @@ + Functions::PRECISION); + + return self::$oneSqrtPi * exp(-$value * $value) * $q2; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 6c1d6c7b..601dafa0 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2716,7 +2716,7 @@ class Statistical } if ((is_numeric($cumulative)) || (is_bool($cumulative))) { if ($cumulative) { - return 0.5 * (1 + Engineering::erfVal(($value - $mean) / ($stdDev * sqrt(2)))); + return 0.5 * (1 + Engineering\Erf::erfValue(($value - $mean) / ($stdDev * sqrt(2)))); } return (1 / (self::SQRT2PI * $stdDev)) * exp(0 - (($value - $mean) ** 2 / (2 * ($stdDev * $stdDev)))); From e824caf85797d8dc49e58c16d064655e9aa13d0c Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sat, 13 Feb 2021 13:09:49 +0100 Subject: [PATCH 053/187] Update Changelog --- CHANGELOG.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe2f4ec5..eb49b512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,19 +23,19 @@ and this project adheres to [Semantic Versioning](https://semver.org). One TextData function is also affected: `REPT()` (str_repeat). - `formatAsDate` correctly matches language metadata, reverting c55272e - - Formulae that previously crashed on sub function call returning excel error value now return said value. The following functions are affected `CUMPRINC()`, `CUMIPMT()`, `AMORLINC()`, `AMORDEGRC()`. - - Adapt some function error return value to match excel's error. The following functions are affected `PPMT()`, `IPMT()`. - -- All related unit tests have been updated to test for those modifications. ### Deprecated -- Nothing. +- Calling many of the Excel formula functions directly rather than through the Calculation Engine. + + The logic for these Functions is now being moved out of the categorised `Database`, `DateTime`, `Engineering`, `Financial`, `Logical`, `LookupRef`, `MathTrig`, `Statistical`, `TextData` and `Web` classes into small, dedicated classes for individual functions or related groups of functions. + + This makes the logic in these classes easier to maintain; and will reduce the memory footprint required to execute formulae when calling these functions. ### Removed @@ -51,8 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) - Fix for not yet implemented data-types in Open Document writer [Issue #1674](https://github.com/PHPOffice/PhpSpreadsheet/issues/1674) - Fix XLSX reader when having a corrupt numeric cell data type [PR #1664](https://github.com/phpoffice/phpspreadsheet/pull/1664) -- Fix on `CUMPRINC()`, `CUMIPMT()`, `AMORLINC()`, `AMORDEGRC()` usage. When those functions called one of `YEARFRAC()`, `PPMT()`, `IPMT()` and they would get back an error -value (represented as a string), trying to use numeral operands (`+`, `/`, `-`, `*`) on said return value and a number (`float or `int`) would fail. +- Fix on `CUMPRINC()`, `CUMIPMT()`, `AMORLINC()`, `AMORDEGRC()` usage. When those functions called one of `YEARFRAC()`, `PPMT()`, `IPMT()` and they would get back an error value (represented as a string), trying to use numeral operands (`+`, `/`, `-`, `*`) on said return value and a number (`float or `int`) would fail. ## 1.16.0 - 2020-12-31 From 42ecc270ecfb85ea7c419481cd3622be2e6d1e7e Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 13 Feb 2021 15:35:07 +0100 Subject: [PATCH 054/187] Extract Permutation functions from the Statistical class into a dedicated Permutations class (#1851) * Extract Permutation functions from the Statistical class into a dedicated Permutations class Retain the original methods in the Statistical class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2 Note that unit tests still point to the Statistical class stubs; these should be modified to use the Permutations class directly when the stubs are removed Also provided a basic implementationof the PERMUTATIONA() Function --- CHANGELOG.md | 1 + .../Calculation/Calculation.php | 4 +- .../Calculation/Statistical.php | 16 +---- .../Calculation/Statistical/Permutations.php | 69 +++++++++++++++++++ .../Statistical/PermutationATest.php | 31 +++++++++ tests/data/Calculation/Statistical/PERMUT.php | 4 ++ .../Calculation/Statistical/PERMUTATIONA.php | 28 ++++++++ 7 files changed, 138 insertions(+), 15 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Permutations.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php create mode 100644 tests/data/Calculation/Statistical/PERMUTATIONA.php diff --git a/CHANGELOG.md b/CHANGELOG.md index eb49b512..ddfd2fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754) - Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) +- Basic implementation of the PERMUTATIONA() Statistical Function ### Changed diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 537b9372..0ef11aa0 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1932,12 +1932,12 @@ class Calculation ], 'PERMUT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'PERMUT'], + 'functionCall' => [Statistical\Permutations::class, 'PERMUT'], 'argumentCount' => '2', ], 'PERMUTATIONA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Permutations::class, 'PERMUTATIONA'], 'argumentCount' => '2', ], 'PHONETIC' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 601dafa0..5792b78f 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2923,6 +2923,8 @@ class Statistical * combinations, for which the internal order is not significant. Use this function * for lottery-style probability calculations. * + * @Deprecated 2.0.0 Use the PERMUT() method in the Statistical\Permutations class instead + * * @param int $numObjs Number of different objects * @param int $numInSet Number of objects in each permutation * @@ -2930,19 +2932,7 @@ class Statistical */ public static function PERMUT($numObjs, $numInSet) { - $numObjs = Functions::flattenSingleValue($numObjs); - $numInSet = Functions::flattenSingleValue($numInSet); - - if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { - $numInSet = floor($numInSet); - if ($numObjs < $numInSet) { - return Functions::NAN(); - } - - return round(MathTrig::FACT($numObjs) / MathTrig::FACT($numObjs - $numInSet)); - } - - return Functions::VALUE(); + return Statistical\Permutations::PERMUT($numObjs, $numInSet); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php new file mode 100644 index 00000000..84c10719 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -0,0 +1,69 @@ + Date: Sat, 13 Feb 2021 15:58:06 +0100 Subject: [PATCH 055/187] Update docs --- src/PhpSpreadsheet/Calculation/functionlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PhpSpreadsheet/Calculation/functionlist.txt b/src/PhpSpreadsheet/Calculation/functionlist.txt index e71d18f4..8fed43a6 100644 --- a/src/PhpSpreadsheet/Calculation/functionlist.txt +++ b/src/PhpSpreadsheet/Calculation/functionlist.txt @@ -276,6 +276,7 @@ PEARSON PERCENTILE PERCENTRANK PERMUT +PERMUTATIONA PHONETIC PI PMT From c54e3e997907f01bf4c227708b98744e80d51d99 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 13 Feb 2021 20:52:20 +0100 Subject: [PATCH 056/187] Extract DELTA() and GESTEP() functions from the Engineering class into a dedicated Comparison classes (#1853) * Extract DELTA() and GESTEP() functions from the Engineering class into a dedicated Comparison classes Retain the original methods in the Engineering class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2 Note that unit tests still point to the Engineering class stubs; these should be modified to use the Erf and ErfC classes directly when the stubs are removed --- .../Calculation/Calculation.php | 6 +- .../Calculation/Engineering.php | 29 ++++----- .../Calculation/Engineering/Compare.php | 63 +++++++++++++++++++ tests/data/Calculation/Engineering/DELTA.php | 5 ++ tests/data/Calculation/Engineering/GESTEP.php | 5 ++ 5 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/Compare.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 0ef11aa0..ae33e45c 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -839,7 +839,7 @@ class Calculation ], 'DELTA' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'DELTA'], + 'functionCall' => [Engineering\Compare::class, 'DELTA'], 'argumentCount' => '1,2', ], 'DEVSQ' => [ @@ -954,7 +954,7 @@ class Calculation ], 'ERFC.PRECISE' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'ERFC'], + 'functionCall' => [Engineering\ErfC::class, 'ERFC'], 'argumentCount' => '1', ], 'ERROR.TYPE' => [ @@ -1196,7 +1196,7 @@ class Calculation ], 'GESTEP' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'GESTEP'], + 'functionCall' => [Engineering\Compare::class, 'GESTEP'], 'argumentCount' => '1,2', ], 'GETPIVOTDATA' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 92b68807..d7ed6e31 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -1091,24 +1091,23 @@ class Engineering * DELTA. * * Tests whether two values are equal. Returns 1 if number1 = number2; returns 0 otherwise. - * Use this function to filter a set of values. For example, by summing several DELTA - * functions you calculate the count of equal pairs. This function is also known as the - * Kronecker Delta function. + * Use this function to filter a set of values. For example, by summing several DELTA + * functions you calculate the count of equal pairs. This function is also known as the + * Kronecker Delta function. * * Excel Function: * DELTA(a[,b]) * + * @Deprecated 2.0.0 Use the DELTA() method in the Engineering\Compare class instead + * * @param float $a the first number * @param float $b The second number. If omitted, b is assumed to be zero. * - * @return int + * @return int|string (string in the event of an error) */ public static function DELTA($a, $b = 0) { - $a = Functions::flattenSingleValue($a); - $b = Functions::flattenSingleValue($b); - - return (int) ($a == $b); + return Engineering\Compare::DELTA($a, $b); } /** @@ -1119,20 +1118,18 @@ class Engineering * * Returns 1 if number >= step; returns 0 (zero) otherwise * Use this function to filter a set of values. For example, by summing several GESTEP - * functions you calculate the count of values that exceed a threshold. + * functions you calculate the count of values that exceed a threshold. + * + * @Deprecated 2.0.0 Use the GESTEP() method in the Engineering\Compare class instead * * @param float $number the value to test against step - * @param float $step The threshold value. - * If you omit a value for step, GESTEP uses zero. + * @param float $step The threshold value. If you omit a value for step, GESTEP uses zero. * - * @return int + * @return int|string (string in the event of an error) */ public static function GESTEP($number, $step = 0) { - $number = Functions::flattenSingleValue($number); - $step = Functions::flattenSingleValue($step); - - return (int) ($number >= $step); + return Engineering\Compare::GESTEP($number, $step); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Compare.php b/src/PhpSpreadsheet/Calculation/Engineering/Compare.php new file mode 100644 index 00000000..d875174e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/Compare.php @@ -0,0 +1,63 @@ += step; returns 0 (zero) otherwise + * Use this function to filter a set of values. For example, by summing several GESTEP + * functions you calculate the count of values that exceed a threshold. + * + * @param float $number the value to test against step + * @param float $step The threshold value. If you omit a value for step, GESTEP uses zero. + * + * @return int|string (string in the event of an error) + */ + public static function GESTEP($number, $step = 0) + { + $number = Functions::flattenSingleValue($number); + $step = Functions::flattenSingleValue($step); + + if (!is_numeric($number) || !is_numeric($step)) { + return Functions::VALUE(); + } + + return (int) ($number >= $step); + } +} diff --git a/tests/data/Calculation/Engineering/DELTA.php b/tests/data/Calculation/Engineering/DELTA.php index 828cc66a..0180c3b9 100644 --- a/tests/data/Calculation/Engineering/DELTA.php +++ b/tests/data/Calculation/Engineering/DELTA.php @@ -126,4 +126,9 @@ return [ 1.5, 1.5, ], + [ + '#VALUE!', + 1, + true, + ], ]; diff --git a/tests/data/Calculation/Engineering/GESTEP.php b/tests/data/Calculation/Engineering/GESTEP.php index b98c66f1..db9bf645 100644 --- a/tests/data/Calculation/Engineering/GESTEP.php +++ b/tests/data/Calculation/Engineering/GESTEP.php @@ -406,4 +406,9 @@ return [ 4.5, 4.5, ], + [ + '#VALUE!', + 1, + true, + ], ]; From cabcfaa52203472b0fde2e0472e3118ceebabc7b Mon Sep 17 00:00:00 2001 From: oleibman Date: Sat, 13 Feb 2021 12:00:08 -0800 Subject: [PATCH 057/187] ROUND Accepts null, false, and true as First Parameter (#1837) * ROUND Accepts null, false, and true as First Parameter Issue #1789 was addressed by PR #1799. In a follow-up discussion, it came to light that ROUND was not handling the unexpected case where the first parameter is an empty cell in the same manner that Excel does. Subsequent investigation showed that a boolean first parameter is permitted. I broadened my investigation to include the following related functions. - ROUNDUP - ROUNDDOWN - MROUND - TRUNC - INT - FLOOR - FLOOR.MATH - FLOOR.PRECISE - CEILING - CEILING.MATH - CEILING.PRECISE All of these allow a NULL first parameter, and all except MROUND allow boolean. For completeness, I will note that all treat null string as invalid. I suspect there are other functions which permit similarly unexpected parameters, but I consider them out of scope for this PR. CEILING.MATH and CEILING.PRECISE were unimplemented, and are now supported as part of this PR. The tests for each of these functions have been re-coded, though all the original test data is still included in the test cases, plus several new cases for each. The new tests now take place as a user would invoke the functions, through a spreadsheet cell rather than a direct call to the appropriate function within Calculation/MathTrig. Aside from being more realistic, the new tests are also more complete. For example, FLOOR.MATH can take from 1-3 arguments, and the existing tests confirmed that the function in Calculation could handle a single argument. However, the function list in Calculation.php erroneously set the number of arguments for FLOOR.MATH to exactly 3, so, if a user tried to get the calculated result of a cell containing FLOOR.MATH(1.2), the result would be an Exception. Aside from the parameter support, there are a few minor code changes. Ods, as well as Gnumeric, allows the omission of the second parameter for FLOAT and CEILING; Excel does not. A potential divide-by-zero error is avoided in CEILING, FLOOR, and FLOORMATH. I will note that it would probably be beneficial in terms of maintainability to break MathTrig up into many individual modules. The same would hold for the other Calculation modules. I would be willing to look into this if you agree that it would be worthwhile. --- .../Calculation/Calculation.php | 36 +-- src/PhpSpreadsheet/Calculation/MathTrig.php | 294 ++++++------------ .../Calculation/MathTrig/Ceiling.php | 68 ++++ .../Calculation/MathTrig/CeilingMath.php | 55 ++++ .../Calculation/MathTrig/CeilingPrecise.php | 39 +++ .../Calculation/MathTrig/Floor.php | 71 +++++ .../Calculation/MathTrig/FloorMath.php | 68 ++++ .../Calculation/MathTrig/FloorPrecise.php | 51 +++ .../Calculation/MathTrig/IntClass.php | 31 ++ .../Calculation/MathTrig/Mround.php | 42 +++ .../Calculation/MathTrig/Round.php | 30 ++ .../Calculation/MathTrig/RoundDown.php | 39 +++ .../Calculation/MathTrig/RoundUp.php | 39 +++ .../Calculation/MathTrig/Trunc.php | 40 +++ src/PhpSpreadsheet/Calculation/TextData.php | 2 +- .../Calculation/functionlist.txt | 2 + src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php | 2 + .../Functions/MathTrig/CeilingMathTest.php | 37 +++ .../Functions/MathTrig/CeilingPreciseTest.php | 37 +++ .../Functions/MathTrig/CeilingTest.php | 57 +++- .../Functions/MathTrig/FloorMathTest.php | 24 +- .../Functions/MathTrig/FloorPreciseTest.php | 24 +- .../Functions/MathTrig/FloorTest.php | 57 +++- .../Functions/MathTrig/IntTest.php | 27 +- .../Functions/MathTrig/MRoundTest.php | 24 +- .../Functions/MathTrig/MovedFunctionsTest.php | 30 ++ .../Functions/MathTrig/RoundDownTest.php | 28 +- .../Functions/MathTrig/RoundTest.php | 19 +- .../Functions/MathTrig/RoundUpTest.php | 28 +- .../Functions/MathTrig/TruncTest.php | 24 +- tests/data/Calculation/MathTrig/CEILING.php | 130 ++------ .../data/Calculation/MathTrig/CEILINGMATH.php | 32 ++ .../Calculation/MathTrig/CEILINGPRECISE.php | 26 ++ tests/data/Calculation/MathTrig/FLOOR.php | 78 ++--- tests/data/Calculation/MathTrig/FLOORMATH.php | 118 ++----- .../Calculation/MathTrig/FLOORPRECISE.php | 80 ++--- tests/data/Calculation/MathTrig/INT.php | 101 ++---- tests/data/Calculation/MathTrig/MROUND.php | 83 ++--- tests/data/Calculation/MathTrig/ROUND.php | 37 ++- tests/data/Calculation/MathTrig/ROUNDDOWN.php | 125 ++------ tests/data/Calculation/MathTrig/ROUNDUP.php | 125 ++------ tests/data/Calculation/MathTrig/TRUNC.php | 124 ++------ 42 files changed, 1352 insertions(+), 1032 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/CeilingMath.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/CeilingPrecise.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Floor.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/FloorMath.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/FloorPrecise.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Mround.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Round.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/RoundDown.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/RoundUp.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php create mode 100644 tests/data/Calculation/MathTrig/CEILINGMATH.php create mode 100644 tests/data/Calculation/MathTrig/CEILINGPRECISE.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index ae33e45c..12826a75 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -463,18 +463,18 @@ class Calculation ], 'CEILING' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'CEILING'], - 'argumentCount' => '2', + 'functionCall' => [MathTrig\Ceiling::class, 'funcCeiling'], + 'argumentCount' => '1-2', // 2 for Excel, 1-2 for Ods/Gnumeric ], 'CEILING.MATH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [Functions::class, 'DUMMY'], - 'argumentCount' => '3', + 'functionCall' => [MathTrig\CeilingMath::class, 'funcCeilingMath'], + 'argumentCount' => '1-3', ], 'CEILING.PRECISE' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [Functions::class, 'DUMMY'], - 'argumentCount' => '2', + 'functionCall' => [MathTrig\CeilingPrecise::class, 'funcCeilingPrecise'], + 'argumentCount' => '1,2', ], 'CELL' => [ 'category' => Category::CATEGORY_INFORMATION, @@ -1069,18 +1069,18 @@ class Calculation ], 'FLOOR' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'FLOOR'], - 'argumentCount' => '2', + 'functionCall' => [MathTrig\Floor::class, 'funcFloor'], + 'argumentCount' => '1-2', // Excel requries 2, Ods/Gnumeric 1-2 ], 'FLOOR.MATH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'FLOORMATH'], - 'argumentCount' => '3', + 'functionCall' => [MathTrig\FloorMath::class, 'funcFloorMath'], + 'argumentCount' => '1-3', ], 'FLOOR.PRECISE' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'FLOORPRECISE'], - 'argumentCount' => '2', + 'functionCall' => [MathTrig\FloorPrecise::class, 'funcFloorPrecise'], + 'argumentCount' => '1-2', ], 'FORECAST' => [ 'category' => Category::CATEGORY_STATISTICAL, @@ -1418,7 +1418,7 @@ class Calculation ], 'INT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'INT'], + 'functionCall' => [MathTrig\IntClass::class, 'funcInt'], 'argumentCount' => '1', ], 'INTERCEPT' => [ @@ -1725,7 +1725,7 @@ class Calculation ], 'MROUND' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'MROUND'], + 'functionCall' => [MathTrig\Mround::class, 'funcMround'], 'argumentCount' => '2', ], 'MULTINOMIAL' => [ @@ -2112,17 +2112,17 @@ class Calculation ], 'ROUND' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinROUND'], + 'functionCall' => [MathTrig\Round::class, 'builtinROUND'], 'argumentCount' => '2', ], 'ROUNDDOWN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ROUNDDOWN'], + 'functionCall' => [MathTrig\RoundDown::class, 'funcRoundDown'], 'argumentCount' => '2', ], 'ROUNDUP' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ROUNDUP'], + 'functionCall' => [MathTrig\RoundUp::class, 'funcRoundUp'], 'argumentCount' => '2', ], 'ROW' => [ @@ -2474,7 +2474,7 @@ class Calculation ], 'TRUNC' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'TRUNC'], + 'functionCall' => [MathTrig\Trunc::class, 'funcTrunc'], 'argumentCount' => '1,2', ], 'TTEST' => [ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 9ce4a752..7a864b97 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -223,34 +223,18 @@ class MathTrig * Excel Function: * CEILING(number[,significance]) * + * @Deprecated 2.0.0 Use the funcCeiling method in the MathTrig\Ceiling class instead + * * @param float $number the number you want to round * @param float $significance the multiple to which you want to round * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function CEILING($number, $significance = null) { - $number = Functions::flattenSingleValue($number); - $significance = Functions::flattenSingleValue($significance); - - if ( - ($significance === null) && - (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) - ) { - $significance = $number / abs($number); - } - - if ((is_numeric($number)) && (is_numeric($significance))) { - if (($number == 0.0) || ($significance == 0.0)) { - return 0.0; - } elseif (self::SIGN($number) == self::SIGN($significance)) { - return ceil($number / $significance) * $significance; - } - - return Functions::NAN(); - } - - return Functions::VALUE(); + return MathTrig\Ceiling::funcCeiling($number, $significance); } /** @@ -312,14 +296,19 @@ class MathTrig } if (is_numeric($number)) { - $significance = 2 * self::SIGN($number); - - return (int) self::CEILING($number, $significance); + return self::getEven((float) $number); } return Functions::VALUE(); } + public static function getEven(float $number): int + { + $significance = 2 * self::returnSign($number); + + return (int) MathTrig\Ceiling::funcCeiling($number, $significance); + } + /** * FACT. * @@ -401,38 +390,18 @@ class MathTrig * Excel Function: * FLOOR(number[,significance]) * + * @Deprecated 2.0.0 Use the funcFloor method in the MathTrig\Floor class instead + * * @param float $number Number to round * @param float $significance Significance * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function FLOOR($number, $significance = null) { - $number = Functions::flattenSingleValue($number); - $significance = Functions::flattenSingleValue($significance); - - if ( - ($significance === null) && - (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) - ) { - $significance = $number / abs($number); - } - - if ((is_numeric($number)) && (is_numeric($significance))) { - if ($significance == 0.0) { - return Functions::DIV0(); - } elseif ($number == 0.0) { - return 0.0; - } elseif (self::SIGN($significance) == 1) { - return floor($number / $significance) * $significance; - } elseif (self::SIGN($number) == -1 && self::SIGN($significance) == -1) { - return floor($number / $significance) * $significance; - } - - return Functions::NAN(); - } - - return Functions::VALUE(); + return MathTrig\Floor::funcFloor($number, $significance); } /** @@ -443,35 +412,19 @@ class MathTrig * Excel Function: * FLOOR.MATH(number[,significance[,mode]]) * + * @Deprecated 2.0.0 Use the funcFloorMath method in the MathTrig\FloorMath class instead + * * @param float $number Number to round * @param float $significance Significance * @param int $mode direction to round negative numbers * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function FLOORMATH($number, $significance = null, $mode = 0) { - $number = Functions::flattenSingleValue($number); - $significance = Functions::flattenSingleValue($significance); - $mode = Functions::flattenSingleValue($mode); - - if (is_numeric($number) && $significance === null) { - $significance = $number / abs($number); - } - - if (is_numeric($number) && is_numeric($significance) && is_numeric($mode)) { - if ($significance == 0.0) { - return Functions::DIV0(); - } elseif ($number == 0.0) { - return 0.0; - } elseif (self::SIGN($significance) == -1 || (self::SIGN($number) == -1 && !empty($mode))) { - return ceil($number / $significance) * $significance; - } - - return floor($number / $significance) * $significance; - } - - return Functions::VALUE(); + return MathTrig\FloorMath::funcFloorMath($number, $significance, $mode); } /** @@ -482,27 +435,18 @@ class MathTrig * Excel Function: * FLOOR.PRECISE(number[,significance]) * + * @Deprecated 2.0.0 Use the funcFloorPrecise method in the MathTrig\FloorPrecise class instead + * * @param float $number Number to round * @param float $significance Significance * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function FLOORPRECISE($number, $significance = 1) { - $number = Functions::flattenSingleValue($number); - $significance = Functions::flattenSingleValue($significance); - - if ((is_numeric($number)) && (is_numeric($significance))) { - if ($significance == 0.0) { - return Functions::DIV0(); - } elseif ($number == 0.0) { - return 0.0; - } - - return floor($number / abs($significance)) * abs($significance); - } - - return Functions::VALUE(); + return MathTrig\FloorPrecise::funcFloorPrecise($number, $significance); } private static function evaluateGCD($a, $b) @@ -510,6 +454,27 @@ class MathTrig return $b ? self::evaluateGCD($b, $a % $b) : $a; } + /** + * INT. + * + * Casts a floating point value to an integer + * + * Excel Function: + * INT(number) + * + * @Deprecated 2.0.0 Use the funcInt method in the MathTrig\IntClass class instead + * + * @param float $number Number to cast to an integer + * + * @return int|string Integer value, or a string containing an error + * + * @codeCoverageIgnore + */ + public static function INT($number) + { + return MathTrig\IntClass::funcInt($number); + } + /** * GCD. * @@ -544,34 +509,6 @@ class MathTrig return $gcd; } - /** - * INT. - * - * Casts a floating point value to an integer - * - * Excel Function: - * INT(number) - * - * @param float $number Number to cast to an integer - * - * @return int|string Integer value, or a string containing an error - */ - public static function INT($number) - { - $number = Functions::flattenSingleValue($number); - - if ($number === null) { - return 0; - } elseif (is_bool($number)) { - return (int) $number; - } - if (is_numeric($number)) { - return (int) floor($number); - } - - return Functions::VALUE(); - } - /** * LCM. * @@ -847,30 +784,18 @@ class MathTrig * * Rounds a number to the nearest multiple of a specified value * + * @Deprecated 2.0.0 Use the funcMround method in the MathTrig\Mround class instead + * * @param float $number Number to round * @param int $multiple Multiple to which you want to round $number * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function MROUND($number, $multiple) { - $number = Functions::flattenSingleValue($number); - $multiple = Functions::flattenSingleValue($multiple); - - if ((is_numeric($number)) && (is_numeric($multiple))) { - if ($number == 0 || $multiple == 0) { - return 0; - } - if ((self::SIGN($number)) == (self::SIGN($multiple))) { - $multiplier = 1 / $multiple; - - return round($number * $multiplier) / $multiplier; - } - - return Functions::NAN(); - } - - return Functions::VALUE(); + return MathTrig\Mround::funcMround($number, $multiple); } /** @@ -928,13 +853,16 @@ class MathTrig } elseif (is_bool($number)) { return 1; } elseif (is_numeric($number)) { - $significance = self::SIGN($number); + $significance = self::returnSign($number); if ($significance == 0) { return 1; } - $result = self::CEILING($number, $significance); - if ($result == self::EVEN($result)) { + $result = MathTrig\Ceiling::funcCeiling($number, $significance); + if (is_string($result)) { + return $result; + } + if ($result == self::getEven((float) $result)) { $result += $significance; } @@ -1104,29 +1032,18 @@ class MathTrig * * Rounds a number up to a specified number of decimal places * + * @Deprecated 2.0.0 Use the funcRoundUp method in the MathTrig\RoundUp class instead + * * @param float $number Number to round * @param int $digits Number of digits to which you want to round $number * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function ROUNDUP($number, $digits) { - $number = Functions::flattenSingleValue($number); - $digits = Functions::flattenSingleValue($digits); - - if ((is_numeric($number)) && (is_numeric($digits))) { - if ($number == 0.0) { - return 0.0; - } - - if ($number < 0.0) { - return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); - } - - return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); - } - - return Functions::VALUE(); + return MathTrig\RoundUp::funcRoundUp($number, $digits); } /** @@ -1134,29 +1051,18 @@ class MathTrig * * Rounds a number down to a specified number of decimal places * + * @Deprecated 2.0.0 Use the funcRoundDown method in the MathTrig\RoundDown class instead + * * @param float $number Number to round * @param int $digits Number of digits to which you want to round $number * * @return float|string Rounded Number, or a string containing an error + * + * @codeCoverageIgnore */ public static function ROUNDDOWN($number, $digits) { - $number = Functions::flattenSingleValue($number); - $digits = Functions::flattenSingleValue($digits); - - if ((is_numeric($number)) && (is_numeric($digits))) { - if ($number == 0.0) { - return 0.0; - } - - if ($number < 0.0) { - return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); - } - - return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); - } - - return Functions::VALUE(); + return MathTrig\RoundDown::funcRoundDown($number, $digits); } /** @@ -1215,16 +1121,17 @@ class MathTrig return (int) $number; } if (is_numeric($number)) { - if ($number == 0.0) { - return 0; - } - - return $number / abs($number); + return self::returnSign($number); } return Functions::VALUE(); } + public static function returnSign(float $number): int + { + return $number ? (($number > 0) ? 1 : -1) : 0; + } + /** * SQRTPI. * @@ -1628,30 +1535,18 @@ class MathTrig * * Truncates value to the number of fractional digits by number_digits. * + * @Deprecated 2.0.0 Use the funcTrunc method in the MathTrig\Trunc class instead + * * @param float $value * @param int $digits * * @return float|string Truncated value, or a string containing an error + * + * @codeCoverageIgnore */ public static function TRUNC($value = 0, $digits = 0) { - $value = Functions::flattenSingleValue($value); - $digits = Functions::flattenSingleValue($digits); - - // Validate parameters - if ((!is_numeric($value)) || (!is_numeric($digits))) { - return Functions::VALUE(); - } - $digits = floor($digits); - - // Truncate - $adjust = 10 ** $digits; - - if (($digits > 0) && (rtrim((int) ((abs($value) - abs((int) $value)) * $adjust), '0') < $adjust / 10)) { - return $value; - } - - return ((int) ($value * $adjust)) / $adjust; + return MathTrig\Trunc::funcTrunc($value, $digits); } /** @@ -1845,20 +1740,18 @@ class MathTrig * * Returns the result of builtin function round after validating args. * + * @Deprecated 2.0.0 Use the builtinRound method in the MathTrig\Round class instead + * * @param mixed $number Should be numeric * @param mixed $precision Should be int * * @return float|string Rounded number + * + * @codeCoverageIgnore */ public static function builtinROUND($number, $precision) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number) || !is_numeric($precision)) { - return Functions::VALUE(); - } - - return round($number, $precision); + return MathTrig\Round::builtinRound($number, $precision); } /** @@ -2245,4 +2138,19 @@ class MathTrig { return abs($number) < 1.0E-12; } + + /** + * Many functions accept null/false/true argument treated as 0/0/1. + * + * @param mixed $number + */ + public static function nullFalseTrueToNumber(&$number): void + { + $number = Functions::flattenSingleValue($number); + if ($number === null) { + $number = 0; + } elseif (is_bool($number)) { + $number = (int) $number; + } + } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php b/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php new file mode 100644 index 00000000..6fdd6165 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php @@ -0,0 +1,68 @@ + 0) && (rtrim((int) ((abs($value) - abs((int) $value)) * $adjust), '0') < $adjust / 10)) { + return $value; + } + + return ((int) ($value * $adjust)) / $adjust; + } +} diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index 16375664..cea15fdc 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -172,7 +172,7 @@ class TextData if ($value < 0) { $round = 0 - $round; } - $value = MathTrig::MROUND($value, $round); + $value = MathTrig\Mround::funcMround($value, $round); } $mask = "$mask;($mask)"; diff --git a/src/PhpSpreadsheet/Calculation/functionlist.txt b/src/PhpSpreadsheet/Calculation/functionlist.txt index 8fed43a6..96c28a97 100644 --- a/src/PhpSpreadsheet/Calculation/functionlist.txt +++ b/src/PhpSpreadsheet/Calculation/functionlist.txt @@ -40,6 +40,8 @@ BITOR BITRSHIFT BITXOR CEILING +CEILING.MATH +CEILING.PRECISE CELL CHAR CHIDIST diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php b/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php index 8f7c07e8..c322dfc7 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php @@ -10,6 +10,7 @@ class Xlfn . '|beta[.]inv' . '|binom[.]dist' . '|binom[.]inv' + . '|ceiling[.]precise' . '|chisq[.]dist' . '|chisq[.]dist[.]rt' . '|chisq[.]inv' @@ -27,6 +28,7 @@ class Xlfn . '|f[.]inv' . '|f[.]inv[.]rt' . '|f[.]test' + . '|floor[.]precise' . '|gamma[.]dist' . '|gamma[.]inv' . '|gammaln[.]precise' diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php new file mode 100644 index 00000000..1d62b8c3 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php @@ -0,0 +1,37 @@ +expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=CEILING.MATH($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerCEILINGMATH() + { + return require 'tests/data/Calculation/MathTrig/CEILINGMATH.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php new file mode 100644 index 00000000..d47670b7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php @@ -0,0 +1,37 @@ +expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=CEILING.PRECISE($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerFLOORPRECISE() + { + return require 'tests/data/Calculation/MathTrig/CEILINGPRECISE.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php index b60d7c30..ad99b5f0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php @@ -2,25 +2,45 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class CeilingTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { + $this->compatibilityMode = Functions::getCompatibilityMode(); Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); } + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); + } + /** * @dataProvider providerCEILING * * @param mixed $expectedResult + * @param string $formula */ - public function testCEILING($expectedResult, ...$args): void + public function testCEILING($expectedResult, $formula): void { - $result = MathTrig::CEILING(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=CEILING($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } @@ -28,4 +48,35 @@ class CeilingTest extends TestCase { return require 'tests/data/Calculation/MathTrig/CEILING.php'; } + + public function testCEILINGGnumeric1Arg(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue('=CEILING(5.1)'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta(6, $result, 1E-12); + } + + public function testCELINGOpenOffice1Arg(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue('=CEILING(5.1)'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta(6, $result, 1E-12); + } + + public function testFLOORExcel1Arg(): void + { + $this->expectException(CalcExp::class); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $sheet->getCell('A1')->setValue('=CEILING(5.1)'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta(6, $result, 1E-12); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php index d7d51b59..ce546159 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php @@ -2,25 +2,31 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class FloorMathTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerFLOORMATH * * @param mixed $expectedResult + * @param string $formula */ - public function testFLOORMATH($expectedResult, ...$args): void + public function testFLOORMATH($expectedResult, $formula): void { - $result = MathTrig::FLOORMATH(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=FLOOR.MATH($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php index ae5a3199..961ca8ae 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php @@ -2,25 +2,31 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class FloorPreciseTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerFLOORPRECISE * * @param mixed $expectedResult + * @param string $formula */ - public function testFLOOR($expectedResult, ...$args): void + public function testFLOORPRECISE($expectedResult, $formula): void { - $result = MathTrig::FLOORPRECISE(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=FLOOR.PRECISE($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php index e66d97ae..82a142c2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php @@ -2,25 +2,45 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class FloorTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { + $this->compatibilityMode = Functions::getCompatibilityMode(); Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); } + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); + } + /** * @dataProvider providerFLOOR * * @param mixed $expectedResult + * @param string $formula */ - public function testFLOOR($expectedResult, ...$args): void + public function testFLOOR($expectedResult, $formula): void { - $result = MathTrig::FLOOR(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=FLOOR($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } @@ -28,4 +48,35 @@ class FloorTest extends TestCase { return require 'tests/data/Calculation/MathTrig/FLOOR.php'; } + + public function testFLOORGnumeric1Arg(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue('=FLOOR(5.1)'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta(5, $result, 1E-12); + } + + public function testFLOOROpenOffice1Arg(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue('=FLOOR(5.1)'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta(5, $result, 1E-12); + } + + public function testFLOORExcel1Arg(): void + { + $this->expectException(CalcExp::class); + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $sheet->getCell('A1')->setValue('=FLOOR(5.1)'); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta(5, $result, 1E-12); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php index f400a7fe..5c0b12c8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php @@ -2,27 +2,32 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class IntTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerINT * * @param mixed $expectedResult - * @param $value + * @param string $formula */ - public function testINT($expectedResult, $value): void + public function testINT($expectedResult, $formula): void { - $result = MathTrig::INT($value); - self::assertEquals($expectedResult, $result); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=INT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } public function providerINT() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php index 32c9c355..87554d06 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php @@ -2,25 +2,31 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class MRoundTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerMROUND * * @param mixed $expectedResult + * @param mixed $formula */ - public function testMROUND($expectedResult, ...$args): void + public function testMROUND($expectedResult, $formula): void { - $result = MathTrig::MROUND(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=MROUND($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php new file mode 100644 index 00000000..d8b55e7c --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php @@ -0,0 +1,30 @@ +expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=ROUNDDOWN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerROUNDDOWN() + public function providerRoundDown() { return require 'tests/data/Calculation/MathTrig/ROUNDDOWN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php index 3cd353a4..dd09bbaa 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php @@ -12,23 +12,20 @@ class RoundTest extends TestCase * @dataProvider providerRound * * @param mixed $expectedResult - * @param mixed $val - * @param mixed $precision + * @param mixed $formula */ - public function testRound($expectedResult, $val = null, $precision = null): void + public function testRound($expectedResult, $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ROUND()'; - } elseif ($precision === null) { - $this->expectException(CalcExp::class); - $formula = "=ROUND($val)"; - } else { - $formula = "=ROUND($val, $precision)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=ROUND($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php index 825fe419..7907be42 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php @@ -2,29 +2,35 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class RoundUpTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** - * @dataProvider providerROUNDUP + * @dataProvider providerRoundUp * * @param mixed $expectedResult + * @param mixed $formula */ - public function testROUNDUP($expectedResult, ...$args): void + public function testRoundUp($expectedResult, $formula): void { - $result = MathTrig::ROUNDUP(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=ROUNDUP($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerROUNDUP() + public function providerRoundUp() { return require 'tests/data/Calculation/MathTrig/ROUNDUP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php index 5fc248cc..37740c0d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php @@ -2,25 +2,31 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class TruncTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerTRUNC * * @param mixed $expectedResult + * @param string $formula */ - public function testTRUNC($expectedResult, ...$args): void + public function testTRUNC($expectedResult, $formula): void { - $result = MathTrig::TRUNC(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=TRUNC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/data/Calculation/MathTrig/CEILING.php b/tests/data/Calculation/MathTrig/CEILING.php index 4005f12b..a4af7df1 100644 --- a/tests/data/Calculation/MathTrig/CEILING.php +++ b/tests/data/Calculation/MathTrig/CEILING.php @@ -1,104 +1,34 @@ Date: Sat, 13 Feb 2021 12:23:58 -0800 Subject: [PATCH 058/187] Support 'Forms' for ROMAN Function (#1828) * Support 'Forms' for ROMAN Function This seems like an exceptionally silly thing for MS to have implemented (Wikipedia on Roman Numerals: "There is no indication this is anything other than an invention by the programmer"). Nevertheless, we can, and therefore probably should, implement it. Not that I can implement it by an algorithm - Excel describes the various extra styles as "more concise", "more concise", "more concise", and "simplified". Nevertheless, since the universe of potential calls is relatively small, it can be implemented as a table of values where the new forms would return a different value than "classic". This table is relatively large, so I have put it its own member to avoid overhead when the function is needed. * Move ROMAN To Its Own Class See discussion in PR #1837 * PHP 8.1 Deprecations PHP8.1 Unit tests failed. 1 line fixes are available for - Shared/Font - Shared/XMLWriter - Style/Color - Writer/HTML The problem is that an error is also reported for a strcmp at line 272 of Cell/Cell. Not only does that line not invoke strcmp, there is no strcmp in all of Cell/Cell, so I don't know what to make of the error message. Oh well, let's fix what can be fixed. Still dealing with the mysterious PHP8.1 unit test failure in Cell\Cell, which seems to have something to do with strcmp. The only uses of strcmp that I can find in src/ are in Calculation. I can't find any use of it in test/ or samples/. So, if this doesn't fix the problem, I may have to give up. --- .../Calculation/Calculation.php | 29 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 48 +- .../Calculation/MathTrig/Roman.php | 853 ++++++++++++++++++ src/PhpSpreadsheet/Shared/Font.php | 2 +- src/PhpSpreadsheet/Shared/StringHelper.php | 2 +- src/PhpSpreadsheet/Shared/XMLWriter.php | 2 +- src/PhpSpreadsheet/Style/Color.php | 2 +- src/PhpSpreadsheet/Writer/Html.php | 2 +- .../Functions/MathTrig/RomanTest.php | 28 +- tests/data/Calculation/MathTrig/ROMAN.php | 89 +- 10 files changed, 978 insertions(+), 79 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Roman.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 12826a75..d0cb6784 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -2107,7 +2107,7 @@ class Calculation ], 'ROMAN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ROMAN'], + 'functionCall' => [MathTrig\Roman::class, 'funcRoman'], 'argumentCount' => '1,2', ], 'ROUND' => [ @@ -4895,7 +4895,7 @@ class Calculation if (is_numeric($operand1) && is_numeric($operand2)) { $result = (abs($operand1 - $operand2) < $this->delta); } else { - $result = strcmp($operand1, $operand2) == 0; + $result = $this->strcmpAllowNull($operand1, $operand2) == 0; } break; @@ -4906,7 +4906,7 @@ class Calculation } elseif ($useLowercaseFirstComparison) { $result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0; } else { - $result = strcmp($operand1, $operand2) >= 0; + $result = $this->strcmpAllowNull($operand1, $operand2) >= 0; } break; @@ -4917,7 +4917,7 @@ class Calculation } elseif ($useLowercaseFirstComparison) { $result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0; } else { - $result = strcmp($operand1, $operand2) <= 0; + $result = $this->strcmpAllowNull($operand1, $operand2) <= 0; } break; @@ -4926,7 +4926,7 @@ class Calculation if (is_numeric($operand1) && is_numeric($operand2)) { $result = (abs($operand1 - $operand2) > 1E-14); } else { - $result = strcmp($operand1, $operand2) != 0; + $result = $this->strcmpAllowNull($operand1, $operand2) != 0; } break; @@ -4943,8 +4943,8 @@ class Calculation /** * Compare two strings in the same way as strcmp() except that lowercase come before uppercase letters. * - * @param string $str1 First string value for the comparison - * @param string $str2 Second string value for the comparison + * @param null|string $str1 First string value for the comparison + * @param null|string $str2 Second string value for the comparison * * @return int */ @@ -4953,7 +4953,20 @@ class Calculation $inversedStr1 = Shared\StringHelper::strCaseReverse($str1); $inversedStr2 = Shared\StringHelper::strCaseReverse($str2); - return strcmp($inversedStr1, $inversedStr2); + return strcmp($inversedStr1 ?? '', $inversedStr2 ?? ''); + } + + /** + * PHP8.1 deprecates passing null to strcmp. + * + * @param null|string $str1 First string value for the comparison + * @param null|string $str2 Second string value for the comparison + * + * @return int + */ + private function strcmpAllowNull($str1, $str2) + { + return strcmp($str1 ?? '', $str2 ?? ''); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 7a864b97..a4b335d1 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -34,11 +34,6 @@ class MathTrig return [(int) $value]; } - private static function romanCut($num, $n) - { - return ($num - ($num % $n)) / $n; - } - private static function strSplit(string $roman): array { $rslt = str_split($roman); @@ -995,36 +990,23 @@ class MathTrig return mt_rand($min, $max); } + /** + * ROMAN. + * + * Converts a number to Roman numeral + * + * @Deprecated 2.0.0 Use the funcRoman method in the MathTrig\Roman class instead + * + * @param mixed $aValue Number to convert + * @param mixed $style Number indicating one of five possible forms + * + * @return string Roman numeral, or a string containing an error + * + * @codeCoverageIgnore + */ public static function ROMAN($aValue, $style = 0) { - $aValue = Functions::flattenSingleValue($aValue); - $style = ($style === null) ? 0 : (int) Functions::flattenSingleValue($style); - if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) { - return Functions::VALUE(); - } - $aValue = (int) $aValue; - if ($aValue == 0) { - return ''; - } - - $mill = ['', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM']; - $cent = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM']; - $tens = ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC']; - $ones = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX']; - - $roman = ''; - while ($aValue > 5999) { - $roman .= 'M'; - $aValue -= 1000; - } - $m = self::romanCut($aValue, 1000); - $aValue %= 1000; - $c = self::romanCut($aValue, 100); - $aValue %= 100; - $t = self::romanCut($aValue, 10); - $aValue %= 10; - - return $roman . $mill[$m] . $cent[$c] . $tens[$t] . $ones[$aValue]; + return MathTrig\Roman::funcRoman($aValue, $style); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php b/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php new file mode 100644 index 00000000..a461001b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php @@ -0,0 +1,853 @@ + ['VL'], + 46 => ['VLI'], + 47 => ['VLII'], + 48 => ['VLIII'], + 49 => ['VLIV', 'IL'], + 95 => ['VC'], + 96 => ['VCI'], + 97 => ['VCII'], + 98 => ['VCIII'], + 99 => ['VCIV', 'IC'], + 145 => ['CVL'], + 146 => ['CVLI'], + 147 => ['CVLII'], + 148 => ['CVLIII'], + 149 => ['CVLIV', 'CIL'], + 195 => ['CVC'], + 196 => ['CVCI'], + 197 => ['CVCII'], + 198 => ['CVCIII'], + 199 => ['CVCIV', 'CIC'], + 245 => ['CCVL'], + 246 => ['CCVLI'], + 247 => ['CCVLII'], + 248 => ['CCVLIII'], + 249 => ['CCVLIV', 'CCIL'], + 295 => ['CCVC'], + 296 => ['CCVCI'], + 297 => ['CCVCII'], + 298 => ['CCVCIII'], + 299 => ['CCVCIV', 'CCIC'], + 345 => ['CCCVL'], + 346 => ['CCCVLI'], + 347 => ['CCCVLII'], + 348 => ['CCCVLIII'], + 349 => ['CCCVLIV', 'CCCIL'], + 395 => ['CCCVC'], + 396 => ['CCCVCI'], + 397 => ['CCCVCII'], + 398 => ['CCCVCIII'], + 399 => ['CCCVCIV', 'CCCIC'], + 445 => ['CDVL'], + 446 => ['CDVLI'], + 447 => ['CDVLII'], + 448 => ['CDVLIII'], + 449 => ['CDVLIV', 'CDIL'], + 450 => ['LD'], + 451 => ['LDI'], + 452 => ['LDII'], + 453 => ['LDIII'], + 454 => ['LDIV'], + 455 => ['LDV'], + 456 => ['LDVI'], + 457 => ['LDVII'], + 458 => ['LDVIII'], + 459 => ['LDIX'], + 460 => ['LDX'], + 461 => ['LDXI'], + 462 => ['LDXII'], + 463 => ['LDXIII'], + 464 => ['LDXIV'], + 465 => ['LDXV'], + 466 => ['LDXVI'], + 467 => ['LDXVII'], + 468 => ['LDXVIII'], + 469 => ['LDXIX'], + 470 => ['LDXX'], + 471 => ['LDXXI'], + 472 => ['LDXXII'], + 473 => ['LDXXIII'], + 474 => ['LDXXIV'], + 475 => ['LDXXV'], + 476 => ['LDXXVI'], + 477 => ['LDXXVII'], + 478 => ['LDXXVIII'], + 479 => ['LDXXIX'], + 480 => ['LDXXX'], + 481 => ['LDXXXI'], + 482 => ['LDXXXII'], + 483 => ['LDXXXIII'], + 484 => ['LDXXXIV'], + 485 => ['LDXXXV'], + 486 => ['LDXXXVI'], + 487 => ['LDXXXVII'], + 488 => ['LDXXXVIII'], + 489 => ['LDXXXIX'], + 490 => ['LDXL', 'XD'], + 491 => ['LDXLI', 'XDI'], + 492 => ['LDXLII', 'XDII'], + 493 => ['LDXLIII', 'XDIII'], + 494 => ['LDXLIV', 'XDIV'], + 495 => ['LDVL', 'XDV', 'VD'], + 496 => ['LDVLI', 'XDVI', 'VDI'], + 497 => ['LDVLII', 'XDVII', 'VDII'], + 498 => ['LDVLIII', 'XDVIII', 'VDIII'], + 499 => ['LDVLIV', 'XDIX', 'VDIV', 'ID'], + 545 => ['DVL'], + 546 => ['DVLI'], + 547 => ['DVLII'], + 548 => ['DVLIII'], + 549 => ['DVLIV', 'DIL'], + 595 => ['DVC'], + 596 => ['DVCI'], + 597 => ['DVCII'], + 598 => ['DVCIII'], + 599 => ['DVCIV', 'DIC'], + 645 => ['DCVL'], + 646 => ['DCVLI'], + 647 => ['DCVLII'], + 648 => ['DCVLIII'], + 649 => ['DCVLIV', 'DCIL'], + 695 => ['DCVC'], + 696 => ['DCVCI'], + 697 => ['DCVCII'], + 698 => ['DCVCIII'], + 699 => ['DCVCIV', 'DCIC'], + 745 => ['DCCVL'], + 746 => ['DCCVLI'], + 747 => ['DCCVLII'], + 748 => ['DCCVLIII'], + 749 => ['DCCVLIV', 'DCCIL'], + 795 => ['DCCVC'], + 796 => ['DCCVCI'], + 797 => ['DCCVCII'], + 798 => ['DCCVCIII'], + 799 => ['DCCVCIV', 'DCCIC'], + 845 => ['DCCCVL'], + 846 => ['DCCCVLI'], + 847 => ['DCCCVLII'], + 848 => ['DCCCVLIII'], + 849 => ['DCCCVLIV', 'DCCCIL'], + 895 => ['DCCCVC'], + 896 => ['DCCCVCI'], + 897 => ['DCCCVCII'], + 898 => ['DCCCVCIII'], + 899 => ['DCCCVCIV', 'DCCCIC'], + 945 => ['CMVL'], + 946 => ['CMVLI'], + 947 => ['CMVLII'], + 948 => ['CMVLIII'], + 949 => ['CMVLIV', 'CMIL'], + 950 => ['LM'], + 951 => ['LMI'], + 952 => ['LMII'], + 953 => ['LMIII'], + 954 => ['LMIV'], + 955 => ['LMV'], + 956 => ['LMVI'], + 957 => ['LMVII'], + 958 => ['LMVIII'], + 959 => ['LMIX'], + 960 => ['LMX'], + 961 => ['LMXI'], + 962 => ['LMXII'], + 963 => ['LMXIII'], + 964 => ['LMXIV'], + 965 => ['LMXV'], + 966 => ['LMXVI'], + 967 => ['LMXVII'], + 968 => ['LMXVIII'], + 969 => ['LMXIX'], + 970 => ['LMXX'], + 971 => ['LMXXI'], + 972 => ['LMXXII'], + 973 => ['LMXXIII'], + 974 => ['LMXXIV'], + 975 => ['LMXXV'], + 976 => ['LMXXVI'], + 977 => ['LMXXVII'], + 978 => ['LMXXVIII'], + 979 => ['LMXXIX'], + 980 => ['LMXXX'], + 981 => ['LMXXXI'], + 982 => ['LMXXXII'], + 983 => ['LMXXXIII'], + 984 => ['LMXXXIV'], + 985 => ['LMXXXV'], + 986 => ['LMXXXVI'], + 987 => ['LMXXXVII'], + 988 => ['LMXXXVIII'], + 989 => ['LMXXXIX'], + 990 => ['LMXL', 'XM'], + 991 => ['LMXLI', 'XMI'], + 992 => ['LMXLII', 'XMII'], + 993 => ['LMXLIII', 'XMIII'], + 994 => ['LMXLIV', 'XMIV'], + 995 => ['LMVL', 'XMV', 'VM'], + 996 => ['LMVLI', 'XMVI', 'VMI'], + 997 => ['LMVLII', 'XMVII', 'VMII'], + 998 => ['LMVLIII', 'XMVIII', 'VMIII'], + 999 => ['LMVLIV', 'XMIX', 'VMIV', 'IM'], + 1045 => ['MVL'], + 1046 => ['MVLI'], + 1047 => ['MVLII'], + 1048 => ['MVLIII'], + 1049 => ['MVLIV', 'MIL'], + 1095 => ['MVC'], + 1096 => ['MVCI'], + 1097 => ['MVCII'], + 1098 => ['MVCIII'], + 1099 => ['MVCIV', 'MIC'], + 1145 => ['MCVL'], + 1146 => ['MCVLI'], + 1147 => ['MCVLII'], + 1148 => ['MCVLIII'], + 1149 => ['MCVLIV', 'MCIL'], + 1195 => ['MCVC'], + 1196 => ['MCVCI'], + 1197 => ['MCVCII'], + 1198 => ['MCVCIII'], + 1199 => ['MCVCIV', 'MCIC'], + 1245 => ['MCCVL'], + 1246 => ['MCCVLI'], + 1247 => ['MCCVLII'], + 1248 => ['MCCVLIII'], + 1249 => ['MCCVLIV', 'MCCIL'], + 1295 => ['MCCVC'], + 1296 => ['MCCVCI'], + 1297 => ['MCCVCII'], + 1298 => ['MCCVCIII'], + 1299 => ['MCCVCIV', 'MCCIC'], + 1345 => ['MCCCVL'], + 1346 => ['MCCCVLI'], + 1347 => ['MCCCVLII'], + 1348 => ['MCCCVLIII'], + 1349 => ['MCCCVLIV', 'MCCCIL'], + 1395 => ['MCCCVC'], + 1396 => ['MCCCVCI'], + 1397 => ['MCCCVCII'], + 1398 => ['MCCCVCIII'], + 1399 => ['MCCCVCIV', 'MCCCIC'], + 1445 => ['MCDVL'], + 1446 => ['MCDVLI'], + 1447 => ['MCDVLII'], + 1448 => ['MCDVLIII'], + 1449 => ['MCDVLIV', 'MCDIL'], + 1450 => ['MLD'], + 1451 => ['MLDI'], + 1452 => ['MLDII'], + 1453 => ['MLDIII'], + 1454 => ['MLDIV'], + 1455 => ['MLDV'], + 1456 => ['MLDVI'], + 1457 => ['MLDVII'], + 1458 => ['MLDVIII'], + 1459 => ['MLDIX'], + 1460 => ['MLDX'], + 1461 => ['MLDXI'], + 1462 => ['MLDXII'], + 1463 => ['MLDXIII'], + 1464 => ['MLDXIV'], + 1465 => ['MLDXV'], + 1466 => ['MLDXVI'], + 1467 => ['MLDXVII'], + 1468 => ['MLDXVIII'], + 1469 => ['MLDXIX'], + 1470 => ['MLDXX'], + 1471 => ['MLDXXI'], + 1472 => ['MLDXXII'], + 1473 => ['MLDXXIII'], + 1474 => ['MLDXXIV'], + 1475 => ['MLDXXV'], + 1476 => ['MLDXXVI'], + 1477 => ['MLDXXVII'], + 1478 => ['MLDXXVIII'], + 1479 => ['MLDXXIX'], + 1480 => ['MLDXXX'], + 1481 => ['MLDXXXI'], + 1482 => ['MLDXXXII'], + 1483 => ['MLDXXXIII'], + 1484 => ['MLDXXXIV'], + 1485 => ['MLDXXXV'], + 1486 => ['MLDXXXVI'], + 1487 => ['MLDXXXVII'], + 1488 => ['MLDXXXVIII'], + 1489 => ['MLDXXXIX'], + 1490 => ['MLDXL', 'MXD'], + 1491 => ['MLDXLI', 'MXDI'], + 1492 => ['MLDXLII', 'MXDII'], + 1493 => ['MLDXLIII', 'MXDIII'], + 1494 => ['MLDXLIV', 'MXDIV'], + 1495 => ['MLDVL', 'MXDV', 'MVD'], + 1496 => ['MLDVLI', 'MXDVI', 'MVDI'], + 1497 => ['MLDVLII', 'MXDVII', 'MVDII'], + 1498 => ['MLDVLIII', 'MXDVIII', 'MVDIII'], + 1499 => ['MLDVLIV', 'MXDIX', 'MVDIV', 'MID'], + 1545 => ['MDVL'], + 1546 => ['MDVLI'], + 1547 => ['MDVLII'], + 1548 => ['MDVLIII'], + 1549 => ['MDVLIV', 'MDIL'], + 1595 => ['MDVC'], + 1596 => ['MDVCI'], + 1597 => ['MDVCII'], + 1598 => ['MDVCIII'], + 1599 => ['MDVCIV', 'MDIC'], + 1645 => ['MDCVL'], + 1646 => ['MDCVLI'], + 1647 => ['MDCVLII'], + 1648 => ['MDCVLIII'], + 1649 => ['MDCVLIV', 'MDCIL'], + 1695 => ['MDCVC'], + 1696 => ['MDCVCI'], + 1697 => ['MDCVCII'], + 1698 => ['MDCVCIII'], + 1699 => ['MDCVCIV', 'MDCIC'], + 1745 => ['MDCCVL'], + 1746 => ['MDCCVLI'], + 1747 => ['MDCCVLII'], + 1748 => ['MDCCVLIII'], + 1749 => ['MDCCVLIV', 'MDCCIL'], + 1795 => ['MDCCVC'], + 1796 => ['MDCCVCI'], + 1797 => ['MDCCVCII'], + 1798 => ['MDCCVCIII'], + 1799 => ['MDCCVCIV', 'MDCCIC'], + 1845 => ['MDCCCVL'], + 1846 => ['MDCCCVLI'], + 1847 => ['MDCCCVLII'], + 1848 => ['MDCCCVLIII'], + 1849 => ['MDCCCVLIV', 'MDCCCIL'], + 1895 => ['MDCCCVC'], + 1896 => ['MDCCCVCI'], + 1897 => ['MDCCCVCII'], + 1898 => ['MDCCCVCIII'], + 1899 => ['MDCCCVCIV', 'MDCCCIC'], + 1945 => ['MCMVL'], + 1946 => ['MCMVLI'], + 1947 => ['MCMVLII'], + 1948 => ['MCMVLIII'], + 1949 => ['MCMVLIV', 'MCMIL'], + 1950 => ['MLM'], + 1951 => ['MLMI'], + 1952 => ['MLMII'], + 1953 => ['MLMIII'], + 1954 => ['MLMIV'], + 1955 => ['MLMV'], + 1956 => ['MLMVI'], + 1957 => ['MLMVII'], + 1958 => ['MLMVIII'], + 1959 => ['MLMIX'], + 1960 => ['MLMX'], + 1961 => ['MLMXI'], + 1962 => ['MLMXII'], + 1963 => ['MLMXIII'], + 1964 => ['MLMXIV'], + 1965 => ['MLMXV'], + 1966 => ['MLMXVI'], + 1967 => ['MLMXVII'], + 1968 => ['MLMXVIII'], + 1969 => ['MLMXIX'], + 1970 => ['MLMXX'], + 1971 => ['MLMXXI'], + 1972 => ['MLMXXII'], + 1973 => ['MLMXXIII'], + 1974 => ['MLMXXIV'], + 1975 => ['MLMXXV'], + 1976 => ['MLMXXVI'], + 1977 => ['MLMXXVII'], + 1978 => ['MLMXXVIII'], + 1979 => ['MLMXXIX'], + 1980 => ['MLMXXX'], + 1981 => ['MLMXXXI'], + 1982 => ['MLMXXXII'], + 1983 => ['MLMXXXIII'], + 1984 => ['MLMXXXIV'], + 1985 => ['MLMXXXV'], + 1986 => ['MLMXXXVI'], + 1987 => ['MLMXXXVII'], + 1988 => ['MLMXXXVIII'], + 1989 => ['MLMXXXIX'], + 1990 => ['MLMXL', 'MXM'], + 1991 => ['MLMXLI', 'MXMI'], + 1992 => ['MLMXLII', 'MXMII'], + 1993 => ['MLMXLIII', 'MXMIII'], + 1994 => ['MLMXLIV', 'MXMIV'], + 1995 => ['MLMVL', 'MXMV', 'MVM'], + 1996 => ['MLMVLI', 'MXMVI', 'MVMI'], + 1997 => ['MLMVLII', 'MXMVII', 'MVMII'], + 1998 => ['MLMVLIII', 'MXMVIII', 'MVMIII'], + 1999 => ['MLMVLIV', 'MXMIX', 'MVMIV', 'MIM'], + 2045 => ['MMVL'], + 2046 => ['MMVLI'], + 2047 => ['MMVLII'], + 2048 => ['MMVLIII'], + 2049 => ['MMVLIV', 'MMIL'], + 2095 => ['MMVC'], + 2096 => ['MMVCI'], + 2097 => ['MMVCII'], + 2098 => ['MMVCIII'], + 2099 => ['MMVCIV', 'MMIC'], + 2145 => ['MMCVL'], + 2146 => ['MMCVLI'], + 2147 => ['MMCVLII'], + 2148 => ['MMCVLIII'], + 2149 => ['MMCVLIV', 'MMCIL'], + 2195 => ['MMCVC'], + 2196 => ['MMCVCI'], + 2197 => ['MMCVCII'], + 2198 => ['MMCVCIII'], + 2199 => ['MMCVCIV', 'MMCIC'], + 2245 => ['MMCCVL'], + 2246 => ['MMCCVLI'], + 2247 => ['MMCCVLII'], + 2248 => ['MMCCVLIII'], + 2249 => ['MMCCVLIV', 'MMCCIL'], + 2295 => ['MMCCVC'], + 2296 => ['MMCCVCI'], + 2297 => ['MMCCVCII'], + 2298 => ['MMCCVCIII'], + 2299 => ['MMCCVCIV', 'MMCCIC'], + 2345 => ['MMCCCVL'], + 2346 => ['MMCCCVLI'], + 2347 => ['MMCCCVLII'], + 2348 => ['MMCCCVLIII'], + 2349 => ['MMCCCVLIV', 'MMCCCIL'], + 2395 => ['MMCCCVC'], + 2396 => ['MMCCCVCI'], + 2397 => ['MMCCCVCII'], + 2398 => ['MMCCCVCIII'], + 2399 => ['MMCCCVCIV', 'MMCCCIC'], + 2445 => ['MMCDVL'], + 2446 => ['MMCDVLI'], + 2447 => ['MMCDVLII'], + 2448 => ['MMCDVLIII'], + 2449 => ['MMCDVLIV', 'MMCDIL'], + 2450 => ['MMLD'], + 2451 => ['MMLDI'], + 2452 => ['MMLDII'], + 2453 => ['MMLDIII'], + 2454 => ['MMLDIV'], + 2455 => ['MMLDV'], + 2456 => ['MMLDVI'], + 2457 => ['MMLDVII'], + 2458 => ['MMLDVIII'], + 2459 => ['MMLDIX'], + 2460 => ['MMLDX'], + 2461 => ['MMLDXI'], + 2462 => ['MMLDXII'], + 2463 => ['MMLDXIII'], + 2464 => ['MMLDXIV'], + 2465 => ['MMLDXV'], + 2466 => ['MMLDXVI'], + 2467 => ['MMLDXVII'], + 2468 => ['MMLDXVIII'], + 2469 => ['MMLDXIX'], + 2470 => ['MMLDXX'], + 2471 => ['MMLDXXI'], + 2472 => ['MMLDXXII'], + 2473 => ['MMLDXXIII'], + 2474 => ['MMLDXXIV'], + 2475 => ['MMLDXXV'], + 2476 => ['MMLDXXVI'], + 2477 => ['MMLDXXVII'], + 2478 => ['MMLDXXVIII'], + 2479 => ['MMLDXXIX'], + 2480 => ['MMLDXXX'], + 2481 => ['MMLDXXXI'], + 2482 => ['MMLDXXXII'], + 2483 => ['MMLDXXXIII'], + 2484 => ['MMLDXXXIV'], + 2485 => ['MMLDXXXV'], + 2486 => ['MMLDXXXVI'], + 2487 => ['MMLDXXXVII'], + 2488 => ['MMLDXXXVIII'], + 2489 => ['MMLDXXXIX'], + 2490 => ['MMLDXL', 'MMXD'], + 2491 => ['MMLDXLI', 'MMXDI'], + 2492 => ['MMLDXLII', 'MMXDII'], + 2493 => ['MMLDXLIII', 'MMXDIII'], + 2494 => ['MMLDXLIV', 'MMXDIV'], + 2495 => ['MMLDVL', 'MMXDV', 'MMVD'], + 2496 => ['MMLDVLI', 'MMXDVI', 'MMVDI'], + 2497 => ['MMLDVLII', 'MMXDVII', 'MMVDII'], + 2498 => ['MMLDVLIII', 'MMXDVIII', 'MMVDIII'], + 2499 => ['MMLDVLIV', 'MMXDIX', 'MMVDIV', 'MMID'], + 2545 => ['MMDVL'], + 2546 => ['MMDVLI'], + 2547 => ['MMDVLII'], + 2548 => ['MMDVLIII'], + 2549 => ['MMDVLIV', 'MMDIL'], + 2595 => ['MMDVC'], + 2596 => ['MMDVCI'], + 2597 => ['MMDVCII'], + 2598 => ['MMDVCIII'], + 2599 => ['MMDVCIV', 'MMDIC'], + 2645 => ['MMDCVL'], + 2646 => ['MMDCVLI'], + 2647 => ['MMDCVLII'], + 2648 => ['MMDCVLIII'], + 2649 => ['MMDCVLIV', 'MMDCIL'], + 2695 => ['MMDCVC'], + 2696 => ['MMDCVCI'], + 2697 => ['MMDCVCII'], + 2698 => ['MMDCVCIII'], + 2699 => ['MMDCVCIV', 'MMDCIC'], + 2745 => ['MMDCCVL'], + 2746 => ['MMDCCVLI'], + 2747 => ['MMDCCVLII'], + 2748 => ['MMDCCVLIII'], + 2749 => ['MMDCCVLIV', 'MMDCCIL'], + 2795 => ['MMDCCVC'], + 2796 => ['MMDCCVCI'], + 2797 => ['MMDCCVCII'], + 2798 => ['MMDCCVCIII'], + 2799 => ['MMDCCVCIV', 'MMDCCIC'], + 2845 => ['MMDCCCVL'], + 2846 => ['MMDCCCVLI'], + 2847 => ['MMDCCCVLII'], + 2848 => ['MMDCCCVLIII'], + 2849 => ['MMDCCCVLIV', 'MMDCCCIL'], + 2895 => ['MMDCCCVC'], + 2896 => ['MMDCCCVCI'], + 2897 => ['MMDCCCVCII'], + 2898 => ['MMDCCCVCIII'], + 2899 => ['MMDCCCVCIV', 'MMDCCCIC'], + 2945 => ['MMCMVL'], + 2946 => ['MMCMVLI'], + 2947 => ['MMCMVLII'], + 2948 => ['MMCMVLIII'], + 2949 => ['MMCMVLIV', 'MMCMIL'], + 2950 => ['MMLM'], + 2951 => ['MMLMI'], + 2952 => ['MMLMII'], + 2953 => ['MMLMIII'], + 2954 => ['MMLMIV'], + 2955 => ['MMLMV'], + 2956 => ['MMLMVI'], + 2957 => ['MMLMVII'], + 2958 => ['MMLMVIII'], + 2959 => ['MMLMIX'], + 2960 => ['MMLMX'], + 2961 => ['MMLMXI'], + 2962 => ['MMLMXII'], + 2963 => ['MMLMXIII'], + 2964 => ['MMLMXIV'], + 2965 => ['MMLMXV'], + 2966 => ['MMLMXVI'], + 2967 => ['MMLMXVII'], + 2968 => ['MMLMXVIII'], + 2969 => ['MMLMXIX'], + 2970 => ['MMLMXX'], + 2971 => ['MMLMXXI'], + 2972 => ['MMLMXXII'], + 2973 => ['MMLMXXIII'], + 2974 => ['MMLMXXIV'], + 2975 => ['MMLMXXV'], + 2976 => ['MMLMXXVI'], + 2977 => ['MMLMXXVII'], + 2978 => ['MMLMXXVIII'], + 2979 => ['MMLMXXIX'], + 2980 => ['MMLMXXX'], + 2981 => ['MMLMXXXI'], + 2982 => ['MMLMXXXII'], + 2983 => ['MMLMXXXIII'], + 2984 => ['MMLMXXXIV'], + 2985 => ['MMLMXXXV'], + 2986 => ['MMLMXXXVI'], + 2987 => ['MMLMXXXVII'], + 2988 => ['MMLMXXXVIII'], + 2989 => ['MMLMXXXIX'], + 2990 => ['MMLMXL', 'MMXM'], + 2991 => ['MMLMXLI', 'MMXMI'], + 2992 => ['MMLMXLII', 'MMXMII'], + 2993 => ['MMLMXLIII', 'MMXMIII'], + 2994 => ['MMLMXLIV', 'MMXMIV'], + 2995 => ['MMLMVL', 'MMXMV', 'MMVM'], + 2996 => ['MMLMVLI', 'MMXMVI', 'MMVMI'], + 2997 => ['MMLMVLII', 'MMXMVII', 'MMVMII'], + 2998 => ['MMLMVLIII', 'MMXMVIII', 'MMVMIII'], + 2999 => ['MMLMVLIV', 'MMXMIX', 'MMVMIV', 'MMIM'], + 3045 => ['MMMVL'], + 3046 => ['MMMVLI'], + 3047 => ['MMMVLII'], + 3048 => ['MMMVLIII'], + 3049 => ['MMMVLIV', 'MMMIL'], + 3095 => ['MMMVC'], + 3096 => ['MMMVCI'], + 3097 => ['MMMVCII'], + 3098 => ['MMMVCIII'], + 3099 => ['MMMVCIV', 'MMMIC'], + 3145 => ['MMMCVL'], + 3146 => ['MMMCVLI'], + 3147 => ['MMMCVLII'], + 3148 => ['MMMCVLIII'], + 3149 => ['MMMCVLIV', 'MMMCIL'], + 3195 => ['MMMCVC'], + 3196 => ['MMMCVCI'], + 3197 => ['MMMCVCII'], + 3198 => ['MMMCVCIII'], + 3199 => ['MMMCVCIV', 'MMMCIC'], + 3245 => ['MMMCCVL'], + 3246 => ['MMMCCVLI'], + 3247 => ['MMMCCVLII'], + 3248 => ['MMMCCVLIII'], + 3249 => ['MMMCCVLIV', 'MMMCCIL'], + 3295 => ['MMMCCVC'], + 3296 => ['MMMCCVCI'], + 3297 => ['MMMCCVCII'], + 3298 => ['MMMCCVCIII'], + 3299 => ['MMMCCVCIV', 'MMMCCIC'], + 3345 => ['MMMCCCVL'], + 3346 => ['MMMCCCVLI'], + 3347 => ['MMMCCCVLII'], + 3348 => ['MMMCCCVLIII'], + 3349 => ['MMMCCCVLIV', 'MMMCCCIL'], + 3395 => ['MMMCCCVC'], + 3396 => ['MMMCCCVCI'], + 3397 => ['MMMCCCVCII'], + 3398 => ['MMMCCCVCIII'], + 3399 => ['MMMCCCVCIV', 'MMMCCCIC'], + 3445 => ['MMMCDVL'], + 3446 => ['MMMCDVLI'], + 3447 => ['MMMCDVLII'], + 3448 => ['MMMCDVLIII'], + 3449 => ['MMMCDVLIV', 'MMMCDIL'], + 3450 => ['MMMLD'], + 3451 => ['MMMLDI'], + 3452 => ['MMMLDII'], + 3453 => ['MMMLDIII'], + 3454 => ['MMMLDIV'], + 3455 => ['MMMLDV'], + 3456 => ['MMMLDVI'], + 3457 => ['MMMLDVII'], + 3458 => ['MMMLDVIII'], + 3459 => ['MMMLDIX'], + 3460 => ['MMMLDX'], + 3461 => ['MMMLDXI'], + 3462 => ['MMMLDXII'], + 3463 => ['MMMLDXIII'], + 3464 => ['MMMLDXIV'], + 3465 => ['MMMLDXV'], + 3466 => ['MMMLDXVI'], + 3467 => ['MMMLDXVII'], + 3468 => ['MMMLDXVIII'], + 3469 => ['MMMLDXIX'], + 3470 => ['MMMLDXX'], + 3471 => ['MMMLDXXI'], + 3472 => ['MMMLDXXII'], + 3473 => ['MMMLDXXIII'], + 3474 => ['MMMLDXXIV'], + 3475 => ['MMMLDXXV'], + 3476 => ['MMMLDXXVI'], + 3477 => ['MMMLDXXVII'], + 3478 => ['MMMLDXXVIII'], + 3479 => ['MMMLDXXIX'], + 3480 => ['MMMLDXXX'], + 3481 => ['MMMLDXXXI'], + 3482 => ['MMMLDXXXII'], + 3483 => ['MMMLDXXXIII'], + 3484 => ['MMMLDXXXIV'], + 3485 => ['MMMLDXXXV'], + 3486 => ['MMMLDXXXVI'], + 3487 => ['MMMLDXXXVII'], + 3488 => ['MMMLDXXXVIII'], + 3489 => ['MMMLDXXXIX'], + 3490 => ['MMMLDXL', 'MMMXD'], + 3491 => ['MMMLDXLI', 'MMMXDI'], + 3492 => ['MMMLDXLII', 'MMMXDII'], + 3493 => ['MMMLDXLIII', 'MMMXDIII'], + 3494 => ['MMMLDXLIV', 'MMMXDIV'], + 3495 => ['MMMLDVL', 'MMMXDV', 'MMMVD'], + 3496 => ['MMMLDVLI', 'MMMXDVI', 'MMMVDI'], + 3497 => ['MMMLDVLII', 'MMMXDVII', 'MMMVDII'], + 3498 => ['MMMLDVLIII', 'MMMXDVIII', 'MMMVDIII'], + 3499 => ['MMMLDVLIV', 'MMMXDIX', 'MMMVDIV', 'MMMID'], + 3545 => ['MMMDVL'], + 3546 => ['MMMDVLI'], + 3547 => ['MMMDVLII'], + 3548 => ['MMMDVLIII'], + 3549 => ['MMMDVLIV', 'MMMDIL'], + 3595 => ['MMMDVC'], + 3596 => ['MMMDVCI'], + 3597 => ['MMMDVCII'], + 3598 => ['MMMDVCIII'], + 3599 => ['MMMDVCIV', 'MMMDIC'], + 3645 => ['MMMDCVL'], + 3646 => ['MMMDCVLI'], + 3647 => ['MMMDCVLII'], + 3648 => ['MMMDCVLIII'], + 3649 => ['MMMDCVLIV', 'MMMDCIL'], + 3695 => ['MMMDCVC'], + 3696 => ['MMMDCVCI'], + 3697 => ['MMMDCVCII'], + 3698 => ['MMMDCVCIII'], + 3699 => ['MMMDCVCIV', 'MMMDCIC'], + 3745 => ['MMMDCCVL'], + 3746 => ['MMMDCCVLI'], + 3747 => ['MMMDCCVLII'], + 3748 => ['MMMDCCVLIII'], + 3749 => ['MMMDCCVLIV', 'MMMDCCIL'], + 3795 => ['MMMDCCVC'], + 3796 => ['MMMDCCVCI'], + 3797 => ['MMMDCCVCII'], + 3798 => ['MMMDCCVCIII'], + 3799 => ['MMMDCCVCIV', 'MMMDCCIC'], + 3845 => ['MMMDCCCVL'], + 3846 => ['MMMDCCCVLI'], + 3847 => ['MMMDCCCVLII'], + 3848 => ['MMMDCCCVLIII'], + 3849 => ['MMMDCCCVLIV', 'MMMDCCCIL'], + 3895 => ['MMMDCCCVC'], + 3896 => ['MMMDCCCVCI'], + 3897 => ['MMMDCCCVCII'], + 3898 => ['MMMDCCCVCIII'], + 3899 => ['MMMDCCCVCIV', 'MMMDCCCIC'], + 3945 => ['MMMCMVL'], + 3946 => ['MMMCMVLI'], + 3947 => ['MMMCMVLII'], + 3948 => ['MMMCMVLIII'], + 3949 => ['MMMCMVLIV', 'MMMCMIL'], + 3950 => ['MMMLM'], + 3951 => ['MMMLMI'], + 3952 => ['MMMLMII'], + 3953 => ['MMMLMIII'], + 3954 => ['MMMLMIV'], + 3955 => ['MMMLMV'], + 3956 => ['MMMLMVI'], + 3957 => ['MMMLMVII'], + 3958 => ['MMMLMVIII'], + 3959 => ['MMMLMIX'], + 3960 => ['MMMLMX'], + 3961 => ['MMMLMXI'], + 3962 => ['MMMLMXII'], + 3963 => ['MMMLMXIII'], + 3964 => ['MMMLMXIV'], + 3965 => ['MMMLMXV'], + 3966 => ['MMMLMXVI'], + 3967 => ['MMMLMXVII'], + 3968 => ['MMMLMXVIII'], + 3969 => ['MMMLMXIX'], + 3970 => ['MMMLMXX'], + 3971 => ['MMMLMXXI'], + 3972 => ['MMMLMXXII'], + 3973 => ['MMMLMXXIII'], + 3974 => ['MMMLMXXIV'], + 3975 => ['MMMLMXXV'], + 3976 => ['MMMLMXXVI'], + 3977 => ['MMMLMXXVII'], + 3978 => ['MMMLMXXVIII'], + 3979 => ['MMMLMXXIX'], + 3980 => ['MMMLMXXX'], + 3981 => ['MMMLMXXXI'], + 3982 => ['MMMLMXXXII'], + 3983 => ['MMMLMXXXIII'], + 3984 => ['MMMLMXXXIV'], + 3985 => ['MMMLMXXXV'], + 3986 => ['MMMLMXXXVI'], + 3987 => ['MMMLMXXXVII'], + 3988 => ['MMMLMXXXVIII'], + 3989 => ['MMMLMXXXIX'], + 3990 => ['MMMLMXL', 'MMMXM'], + 3991 => ['MMMLMXLI', 'MMMXMI'], + 3992 => ['MMMLMXLII', 'MMMXMII'], + 3993 => ['MMMLMXLIII', 'MMMXMIII'], + 3994 => ['MMMLMXLIV', 'MMMXMIV'], + 3995 => ['MMMLMVL', 'MMMXMV', 'MMMVM'], + 3996 => ['MMMLMVLI', 'MMMXMVI', 'MMMVMI'], + 3997 => ['MMMLMVLII', 'MMMXMVII', 'MMMVMII'], + 3998 => ['MMMLMVLIII', 'MMMXMVIII', 'MMMVMIII'], + 3999 => ['MMMLMVLIV', 'MMMXMIX', 'MMMVMIV', 'MMMIM'], + ]; + private const THOUSANDS = ['', 'M', 'MM', 'MMM']; + private const HUNDREDS = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM']; + private const TENS = ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC']; + private const ONES = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX']; + const MAX_ROMAN_VALUE = 3999; + const MAX_ROMAN_STYLE = 4; + + private static function romanCut($num, $n) + { + return ($num - ($num % $n)) / $n; + } + + private static function valueOk(int $aValue, int $style): string + { + $origValue = $aValue; + $m = self::romanCut($aValue, 1000); + $aValue %= 1000; + $c = self::romanCut($aValue, 100); + $aValue %= 100; + $t = self::romanCut($aValue, 10); + $aValue %= 10; + $result = self::THOUSANDS[$m] . self::HUNDREDS[$c] . self::TENS[$t] . self::ONES[$aValue]; + if ($style > 0) { + if (array_key_exists($origValue, self::VALUES)) { + $arr = self::VALUES[$origValue]; + $idx = min($style, count($arr)) - 1; + $result = $arr[$idx]; + } + } + + return $result; + } + + private static function styleOk(int $aValue, int $style): string + { + return ($aValue < 0 || $aValue > self::MAX_ROMAN_VALUE) ? Functions::VALUE() : self::valueOk($aValue, $style); + } + + public static function calculateRoman(int $aValue, int $style): string + { + return ($style < 0 || $style > self::MAX_ROMAN_STYLE) ? Functions::VALUE() : self::styleOk($aValue, $style); + } + + /** + * ROMAN. + * + * Converts a number to Roman numeral + * + * @param mixed $aValue Number to convert + * @param mixed $style Number indicating one of five possible forms + * + * @return string Roman numeral, or a string containing an error + */ + public static function funcRoman($aValue, $style = 0) + { + $aValue = Functions::flattenSingleValue($aValue); + self::nullFalseTrueToNumber($aValue); + $style = Functions::flattenSingleValue($style); + if (is_bool($style)) { + $style = $style ? 0 : 4; + } + if (!is_numeric($aValue) || !is_numeric($style)) { + return Functions::VALUE(); + } + + return self::calculateRoman((int) $aValue, (int) $style); + } + + /** + * Many functions accept null/false/true argument treated as 0/0/1. + * + * @param mixed $number + */ + private static function nullFalseTrueToNumber(&$number): void + { + $number = Functions::flattenSingleValue($number); + if ($number === null) { + $number = 0; + } elseif (is_bool($number)) { + $number = (int) $number; + } + } +} diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index 821aea98..162e9730 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -232,7 +232,7 @@ class Font } // Special case if there are one or more newline characters ("\n") - if (strpos($cellText, "\n") !== false) { + if (strpos($cellText ?? '', "\n") !== false) { $lineTexts = explode("\n", $cellText); $lineWidths = []; foreach ($lineTexts as $lineText) { diff --git a/src/PhpSpreadsheet/Shared/StringHelper.php b/src/PhpSpreadsheet/Shared/StringHelper.php index 9ae32413..a3cc359b 100644 --- a/src/PhpSpreadsheet/Shared/StringHelper.php +++ b/src/PhpSpreadsheet/Shared/StringHelper.php @@ -464,7 +464,7 @@ class StringHelper */ public static function countCharacters($value, $enc = 'UTF-8') { - return mb_strlen($value, $enc); + return mb_strlen($value ?? '', $enc); } /** diff --git a/src/PhpSpreadsheet/Shared/XMLWriter.php b/src/PhpSpreadsheet/Shared/XMLWriter.php index 4f7a6a06..c35b7820 100644 --- a/src/PhpSpreadsheet/Shared/XMLWriter.php +++ b/src/PhpSpreadsheet/Shared/XMLWriter.php @@ -87,6 +87,6 @@ class XMLWriter extends \XMLWriter $text = implode("\n", $text); } - return $this->writeRaw(htmlspecialchars($text)); + return $this->writeRaw(htmlspecialchars($text ?? '')); } } diff --git a/src/PhpSpreadsheet/Style/Color.php b/src/PhpSpreadsheet/Style/Color.php index ad598f11..acff2e0b 100644 --- a/src/PhpSpreadsheet/Style/Color.php +++ b/src/PhpSpreadsheet/Style/Color.php @@ -167,7 +167,7 @@ class Color extends Supervisor return $this->getSharedComponent()->getRGB(); } - return substr($this->argb, 2); + return substr($this->argb ?? '', 2); } /** diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index e9de2ce6..19dfc558 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -1323,7 +1323,7 @@ class Html extends BaseWriter [$this, 'formatColor'] ); if ($cellData === $origData) { - $cellData = htmlspecialchars($cellData); + $cellData = htmlspecialchars($cellData ?? ''); } if ($pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSuperscript()) { $cellData = '' . $cellData . ''; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php index c74daa32..e913e5d7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php @@ -2,25 +2,28 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class RomanTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerROMAN * * @param mixed $expectedResult + * @param mixed $formula */ - public function testROMAN($expectedResult, ...$args): void + public function testROMAN($expectedResult, $formula): void { - $result = MathTrig::ROMAN(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A3', 49); + $sheet->getCell('A1')->setValue("=ROMAN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +31,11 @@ class RomanTest extends TestCase { return require 'tests/data/Calculation/MathTrig/ROMAN.php'; } + + // Confirm that deprecated stub left in MathTrig works. + // Delete this test when stub is finally deleted. + public function testDeprecated(): void + { + self::assertEquals('I', \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROMAN(1)); + } } diff --git a/tests/data/Calculation/MathTrig/ROMAN.php b/tests/data/Calculation/MathTrig/ROMAN.php index 0aea8bda..d73868ca 100644 --- a/tests/data/Calculation/MathTrig/ROMAN.php +++ b/tests/data/Calculation/MathTrig/ROMAN.php @@ -1,28 +1,69 @@ Date: Sat, 13 Feb 2021 22:08:22 +0100 Subject: [PATCH 059/187] Additional Office 365 functions for Excel added in 2020 --- src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php b/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php index c322dfc7..c88ef245 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php @@ -140,6 +140,11 @@ class Xlfn . '|unique' . '|xlookup' . '|xmatch' + . '|arraytotext' + . '|call' + . '|let' + . '|register[.]id' + . '|valuetotext' . ')(?=\\s*[(])/i'; /** From c407ff6fe7822e6fcadfa4e7fa1ebe4d95ca309e Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 14 Feb 2021 11:55:21 +0100 Subject: [PATCH 060/187] Start extracting Logical Excel functions into separate groups in dedicated classes (#1855) * Start extracting Logical Excel functions into separate groups in dedicated classes * Extracting remaining Logical Excel functions into separate groups in dedicated classes --- .../Calculation/Calculation.php | 22 +- src/PhpSpreadsheet/Calculation/Logical.php | 230 +++++------------- .../Calculation/Logical/Boolean.php | 36 +++ .../Calculation/Logical/Conditional.php | 181 ++++++++++++++ .../Calculation/Logical/Operations.php | 198 +++++++++++++++ 5 files changed, 485 insertions(+), 182 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Logical/Boolean.php create mode 100644 src/PhpSpreadsheet/Calculation/Logical/Conditional.php create mode 100644 src/PhpSpreadsheet/Calculation/Logical/Operations.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index d0cb6784..7868ec5e 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -283,7 +283,7 @@ class Calculation ], 'AND' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'logicalAnd'], + 'functionCall' => [Logical\Operations::class, 'logicalAnd'], 'argumentCount' => '1+', ], 'ARABIC' => [ @@ -999,7 +999,7 @@ class Calculation ], 'FALSE' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'FALSE'], + 'functionCall' => [Logical\Boolean::class, 'FALSE'], 'argumentCount' => '0', ], 'FDIST' => [ @@ -1257,22 +1257,22 @@ class Calculation ], 'IF' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'statementIf'], + 'functionCall' => [Logical\Conditional::class, 'statementIf'], 'argumentCount' => '1-3', ], 'IFERROR' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'IFERROR'], + 'functionCall' => [Logical\Conditional::class, 'IFERROR'], 'argumentCount' => '2', ], 'IFNA' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'IFNA'], + 'functionCall' => [Logical\Conditional::class, 'IFNA'], 'argumentCount' => '2', ], 'IFS' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'IFS'], + 'functionCall' => [Logical\Conditional::class, 'IFS'], 'argumentCount' => '2+', ], 'IMABS' => [ @@ -1815,7 +1815,7 @@ class Calculation ], 'NOT' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'NOT'], + 'functionCall' => [Logical\Operations::class, 'NOT'], 'argumentCount' => '1', ], 'NOW' => [ @@ -1887,7 +1887,7 @@ class Calculation ], 'OR' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'logicalOr'], + 'functionCall' => [Logical\Operations::class, 'logicalOr'], 'argumentCount' => '1+', ], 'PDURATION' => [ @@ -2349,7 +2349,7 @@ class Calculation ], 'SWITCH' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'statementSwitch'], + 'functionCall' => [Logical\Conditional::class, 'statementSwitch'], 'argumentCount' => '3+', ], 'SYD' => [ @@ -2469,7 +2469,7 @@ class Calculation ], 'TRUE' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'TRUE'], + 'functionCall' => [Logical\Boolean::class, 'TRUE'], 'argumentCount' => '0', ], 'TRUNC' => [ @@ -2619,7 +2619,7 @@ class Calculation ], 'XOR' => [ 'category' => Category::CATEGORY_LOGICAL, - 'functionCall' => [Logical::class, 'logicalXor'], + 'functionCall' => [Logical\Operations::class, 'logicalXor'], 'argumentCount' => '1+', ], 'YEAR' => [ diff --git a/src/PhpSpreadsheet/Calculation/Logical.php b/src/PhpSpreadsheet/Calculation/Logical.php index 69c543ce..802ceb26 100644 --- a/src/PhpSpreadsheet/Calculation/Logical.php +++ b/src/PhpSpreadsheet/Calculation/Logical.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\Logical\Boolean; + class Logical { /** @@ -12,11 +14,13 @@ class Logical * Excel Function: * =TRUE() * + * @Deprecated Use the TRUE() method in the Logical\Boolean class instead + * * @return bool True */ - public static function true() + public static function true(): bool { - return true; + return Boolean::true(); } /** @@ -27,37 +31,13 @@ class Logical * Excel Function: * =FALSE() * + * @Deprecated Use the FALSE() method in the Logical\Boolean class instead + * * @return bool False */ - public static function false() + public static function false(): bool { - return false; - } - - private static function countTrueValues(array $args) - { - $returnValue = 0; - - foreach ($args as $arg) { - // Is it a boolean value? - if (is_bool($arg)) { - $returnValue += $arg; - } elseif ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += ((int) $arg != 0); - } elseif (is_string($arg)) { - $arg = strtoupper($arg); - if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) { - $arg = true; - } elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) { - $arg = false; - } else { - return Functions::VALUE(); - } - $returnValue += ($arg != 0); - } - } - - return $returnValue; + return Boolean::false(); } /** @@ -73,8 +53,10 @@ class Logical * * Boolean arguments are treated as True or False as appropriate * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @Deprecated Use the logicalAnd() method in the Logical\Operations class instead * * @param mixed ...$args Data values * @@ -82,23 +64,7 @@ class Logical */ public static function logicalAnd(...$args) { - $args = Functions::flattenArray($args); - - if (count($args) == 0) { - return Functions::VALUE(); - } - - $args = array_filter($args, function ($value) { - return $value !== null || (is_string($value) && trim($value) == ''); - }); - $argCount = count($args); - - $returnValue = self::countTrueValues($args); - if (is_string($returnValue)) { - return $returnValue; - } - - return ($returnValue > 0) && ($returnValue == $argCount); + return Logical\Operations::logicalAnd(...$args); } /** @@ -114,8 +80,10 @@ class Logical * * Boolean arguments are treated as True or False as appropriate * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @Deprecated Use the logicalOr() method in the Logical\Operations class instead * * @param mixed $args Data values * @@ -123,29 +91,15 @@ class Logical */ public static function logicalOr(...$args) { - $args = Functions::flattenArray($args); - - if (count($args) == 0) { - return Functions::VALUE(); - } - - $args = array_filter($args, function ($value) { - return $value !== null || (is_string($value) && trim($value) == ''); - }); - - $returnValue = self::countTrueValues($args); - if (is_string($returnValue)) { - return $returnValue; - } - - return $returnValue > 0; + return Logical\Operations::logicalOr(...$args); } /** * LOGICAL_XOR. * * Returns the Exclusive Or logical operation for one or more supplied conditions. - * i.e. the Xor function returns TRUE if an odd number of the supplied conditions evaluate to TRUE, and FALSE otherwise. + * i.e. the Xor function returns TRUE if an odd number of the supplied conditions evaluate to TRUE, + * and FALSE otherwise. * * Excel Function: * =XOR(logical1[,logical2[, ...]]) @@ -155,8 +109,10 @@ class Logical * * Boolean arguments are treated as True or False as appropriate * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @Deprecated Use the logicalXor() method in the Logical\Operations class instead * * @param mixed $args Data values * @@ -164,22 +120,7 @@ class Logical */ public static function logicalXor(...$args) { - $args = Functions::flattenArray($args); - - if (count($args) == 0) { - return Functions::VALUE(); - } - - $args = array_filter($args, function ($value) { - return $value !== null || (is_string($value) && trim($value) == ''); - }); - - $returnValue = self::countTrueValues($args); - if (is_string($returnValue)) { - return $returnValue; - } - - return $returnValue % 2 == 1; + return Logical\Operations::logicalXor(...$args); } /** @@ -194,8 +135,10 @@ class Logical * * Boolean arguments are treated as True or False as appropriate * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False - * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds - * the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @Deprecated Use the NOT() method in the Logical\Operations class instead * * @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE * @@ -203,20 +146,7 @@ class Logical */ public static function NOT($logical = false) { - $logical = Functions::flattenSingleValue($logical); - - if (is_string($logical)) { - $logical = strtoupper($logical); - if (($logical == 'TRUE') || ($logical == Calculation::getTRUE())) { - return false; - } elseif (($logical == 'FALSE') || ($logical == Calculation::getFALSE())) { - return true; - } - - return Functions::VALUE(); - } - - return !$logical; + return Logical\Operations::NOT($logical); } /** @@ -232,18 +162,20 @@ class Logical * the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE. * This argument can use any comparison calculation operator. * ReturnIfTrue is the value that is returned if condition evaluates to TRUE. - * For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE, - * then the IF function returns the text "Within budget" - * If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use - * the logical value TRUE for this argument. + * For example, if this argument is the text string "Within budget" and the condition argument + * evaluates to TRUE, then the IF function returns the text "Within budget" + * If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). + * To display the word TRUE, use the logical value TRUE for this argument. * ReturnIfTrue can be another formula. * ReturnIfFalse is the value that is returned if condition evaluates to FALSE. - * For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE, - * then the IF function returns the text "Over budget". + * For example, if this argument is the text string "Over budget" and the condition argument + * evaluates to FALSE, then the IF function returns the text "Over budget". * If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned. * If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned. * ReturnIfFalse can be another formula. * + * @Deprecated Use the statementIf() method in the Logical\Conditional class instead + * * @param mixed $condition Condition to evaluate * @param mixed $returnIfTrue Value to return when condition is true * @param mixed $returnIfFalse Optional value to return when condition is false @@ -252,15 +184,7 @@ class Logical */ public static function statementIf($condition = true, $returnIfTrue = 0, $returnIfFalse = false) { - if (Functions::isError($condition)) { - return $condition; - } - - $condition = ($condition === null) ? true : (bool) Functions::flattenSingleValue($condition); - $returnIfTrue = ($returnIfTrue === null) ? 0 : Functions::flattenSingleValue($returnIfTrue); - $returnIfFalse = ($returnIfFalse === null) ? false : Functions::flattenSingleValue($returnIfFalse); - - return ($condition) ? $returnIfTrue : $returnIfFalse; + return Logical\Conditional::statementIf($condition, $returnIfTrue, $returnIfFalse); } /** @@ -274,11 +198,16 @@ class Logical * Expression * The expression to compare to a list of values. * value1, value2, ... value_n - * A list of values that are compared to expression. The SWITCH function is looking for the first value that matches the expression. + * A list of values that are compared to expression. + * The SWITCH function is looking for the first value that matches the expression. * result1, result2, ... result_n - * A list of results. The SWITCH function returns the corresponding result when a value matches expression. + * A list of results. The SWITCH function returns the corresponding result when a value + * matches expression. * default - * Optional. It is the default to return if expression does not match any of the values (value1, value2, ... value_n). + * Optional. It is the default to return if expression does not match any of the values + * (value1, value2, ... value_n). + * + * @Deprecated Use the statementSwitch() method in the Logical\Conditional class instead * * @param mixed $arguments Statement arguments * @@ -286,33 +215,7 @@ class Logical */ public static function statementSwitch(...$arguments) { - $result = Functions::VALUE(); - - if (count($arguments) > 0) { - $targetValue = Functions::flattenSingleValue($arguments[0]); - $argc = count($arguments) - 1; - $switchCount = floor($argc / 2); - $switchSatisfied = false; - $hasDefaultClause = $argc % 2 !== 0; - $defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1]; - - if ($switchCount) { - for ($index = 0; $index < $switchCount; ++$index) { - if ($targetValue == $arguments[$index * 2 + 1]) { - $result = $arguments[$index * 2 + 2]; - $switchSatisfied = true; - - break; - } - } - } - - if (!$switchSatisfied) { - $result = $hasDefaultClause ? $defaultClause : Functions::NA(); - } - } - - return $result; + return Logical\Conditional::statementSwitch(...$arguments); } /** @@ -321,6 +224,8 @@ class Logical * Excel Function: * =IFERROR(testValue,errorpart) * + * @Deprecated Use the IFERROR() method in the Logical\Conditional class instead + * * @param mixed $testValue Value to check, is also the value returned when no error * @param mixed $errorpart Value to return when testValue is an error condition * @@ -328,10 +233,7 @@ class Logical */ public static function IFERROR($testValue = '', $errorpart = '') { - $testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue); - $errorpart = ($errorpart === null) ? '' : Functions::flattenSingleValue($errorpart); - - return self::statementIf(Functions::isError($testValue), $errorpart, $testValue); + return Logical\Conditional::IFERROR($testValue, $errorpart); } /** @@ -340,6 +242,8 @@ class Logical * Excel Function: * =IFNA(testValue,napart) * + * @Deprecated Use the IFNA() method in the Logical\Conditional class instead + * * @param mixed $testValue Value to check, is also the value returned when not an NA * @param mixed $napart Value to return when testValue is an NA condition * @@ -347,10 +251,7 @@ class Logical */ public static function IFNA($testValue = '', $napart = '') { - $testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue); - $napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart); - - return self::statementIf(Functions::isNa($testValue), $napart, $testValue); + return Logical\Conditional::IFNA($testValue, $napart); } /** @@ -364,27 +265,14 @@ class Logical * returnIfTrue1 ... returnIfTrue_n * Value returned if corresponding testValue (nth) was true * + * @Deprecated Use the IFS() method in the Logical\Conditional class instead + * * @param mixed ...$arguments Statement arguments * * @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A if none of testValues was true */ public static function IFS(...$arguments) { - if (count($arguments) % 2 != 0) { - return Functions::NA(); - } - // We use instance of Exception as a falseValue in order to prevent string collision with value in cell - $falseValueException = new Exception(); - for ($i = 0; $i < count($arguments); $i += 2) { - $testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]); - $returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]); - $result = self::statementIf($testValue, $returnIfTrue, $falseValueException); - - if ($result !== $falseValueException) { - return $result; - } - } - - return Functions::NA(); + return Logical\Conditional::IFS(...$arguments); } } diff --git a/src/PhpSpreadsheet/Calculation/Logical/Boolean.php b/src/PhpSpreadsheet/Calculation/Logical/Boolean.php new file mode 100644 index 00000000..8f1e9354 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Logical/Boolean.php @@ -0,0 +1,36 @@ + 0) { + $targetValue = Functions::flattenSingleValue($arguments[0]); + $argc = count($arguments) - 1; + $switchCount = floor($argc / 2); + $switchSatisfied = false; + $hasDefaultClause = $argc % 2 !== 0; + $defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1]; + + if ($switchCount) { + for ($index = 0; $index < $switchCount; ++$index) { + if ($targetValue == $arguments[$index * 2 + 1]) { + $result = $arguments[$index * 2 + 2]; + $switchSatisfied = true; + + break; + } + } + } + + if (!$switchSatisfied) { + $result = $hasDefaultClause ? $defaultClause : Functions::NA(); + } + } + + return $result; + } + + /** + * IFERROR. + * + * Excel Function: + * =IFERROR(testValue,errorpart) + * + * @param mixed $testValue Value to check, is also the value returned when no error + * @param mixed $errorpart Value to return when testValue is an error condition + * + * @return mixed The value of errorpart or testValue determined by error condition + */ + public static function IFERROR($testValue = '', $errorpart = '') + { + $testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue); + $errorpart = ($errorpart === null) ? '' : Functions::flattenSingleValue($errorpart); + + return self::statementIf(Functions::isError($testValue), $errorpart, $testValue); + } + + /** + * IFNA. + * + * Excel Function: + * =IFNA(testValue,napart) + * + * @param mixed $testValue Value to check, is also the value returned when not an NA + * @param mixed $napart Value to return when testValue is an NA condition + * + * @return mixed The value of errorpart or testValue determined by error condition + */ + public static function IFNA($testValue = '', $napart = '') + { + $testValue = ($testValue === null) ? '' : Functions::flattenSingleValue($testValue); + $napart = ($napart === null) ? '' : Functions::flattenSingleValue($napart); + + return self::statementIf(Functions::isNa($testValue), $napart, $testValue); + } + + /** + * IFS. + * + * Excel Function: + * =IFS(testValue1;returnIfTrue1;testValue2;returnIfTrue2;...;testValue_n;returnIfTrue_n) + * + * testValue1 ... testValue_n + * Conditions to Evaluate + * returnIfTrue1 ... returnIfTrue_n + * Value returned if corresponding testValue (nth) was true + * + * @param mixed ...$arguments Statement arguments + * + * @return mixed|string The value of returnIfTrue_n, if testValue_n was true. #N/A if none of testValues was true + */ + public static function IFS(...$arguments) + { + if (count($arguments) % 2 != 0) { + return Functions::NA(); + } + // We use instance of Exception as a falseValue in order to prevent string collision with value in cell + $falseValueException = new Exception(); + for ($i = 0; $i < count($arguments); $i += 2) { + $testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]); + $returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]); + $result = self::statementIf($testValue, $returnIfTrue, $falseValueException); + + if ($result !== $falseValueException) { + return $result; + } + } + + return Functions::NA(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Logical/Operations.php b/src/PhpSpreadsheet/Calculation/Logical/Operations.php new file mode 100644 index 00000000..6bfb6a54 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Logical/Operations.php @@ -0,0 +1,198 @@ + 0) && ($returnValue == $argCount); + } + + /** + * LOGICAL_OR. + * + * Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE. + * + * Excel Function: + * =OR(logical1[,logical2[, ...]]) + * + * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays + * or references that contain logical values. + * + * Boolean arguments are treated as True or False as appropriate + * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @param mixed $args Data values + * + * @return bool|string the logical OR of the arguments + */ + public static function logicalOr(...$args) + { + $args = Functions::flattenArray($args); + + if (count($args) == 0) { + return Functions::VALUE(); + } + + $args = array_filter($args, function ($value) { + return $value !== null || (is_string($value) && trim($value) == ''); + }); + + $returnValue = self::countTrueValues($args); + if (is_string($returnValue)) { + return $returnValue; + } + + return $returnValue > 0; + } + + /** + * LOGICAL_XOR. + * + * Returns the Exclusive Or logical operation for one or more supplied conditions. + * i.e. the Xor function returns TRUE if an odd number of the supplied conditions evaluate to TRUE, + * and FALSE otherwise. + * + * Excel Function: + * =XOR(logical1[,logical2[, ...]]) + * + * The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays + * or references that contain logical values. + * + * Boolean arguments are treated as True or False as appropriate + * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @param mixed $args Data values + * + * @return bool|string the logical XOR of the arguments + */ + public static function logicalXor(...$args) + { + $args = Functions::flattenArray($args); + + if (count($args) == 0) { + return Functions::VALUE(); + } + + $args = array_filter($args, function ($value) { + return $value !== null || (is_string($value) && trim($value) == ''); + }); + + $returnValue = self::countTrueValues($args); + if (is_string($returnValue)) { + return $returnValue; + } + + return $returnValue % 2 == 1; + } + + /** + * NOT. + * + * Returns the boolean inverse of the argument. + * + * Excel Function: + * =NOT(logical) + * + * The argument must evaluate to a logical value such as TRUE or FALSE + * + * Boolean arguments are treated as True or False as appropriate + * Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False + * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string + * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value + * + * @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE + * + * @return bool|string the boolean inverse of the argument + */ + public static function NOT($logical = false) + { + $logical = Functions::flattenSingleValue($logical); + + if (is_string($logical)) { + $logical = mb_strtoupper($logical, 'UTF-8'); + if (($logical == 'TRUE') || ($logical == Calculation::getTRUE())) { + return false; + } elseif (($logical == 'FALSE') || ($logical == Calculation::getFALSE())) { + return true; + } + + return Functions::VALUE(); + } + + return !$logical; + } + + /** + * @return int|string + */ + private static function countTrueValues(array $args) + { + $trueValueCount = 0; + + foreach ($args as $arg) { + // 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)) { + $arg = mb_strtoupper($arg, 'UTF-8'); + if (($arg == 'TRUE') || ($arg == Calculation::getTRUE())) { + $arg = true; + } elseif (($arg == 'FALSE') || ($arg == Calculation::getFALSE())) { + $arg = false; + } else { + return Functions::VALUE(); + } + $trueValueCount += ($arg != 0); + } + } + + return $trueValueCount; + } +} From f2778179552b71fdefd342b8128745302893b0fa Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 14 Feb 2021 16:09:09 +0100 Subject: [PATCH 061/187] Update deprecation notices to reflect deprecated from the next release (#1856) * Update deprecation notices to reflect deprecated from the next release --- .../Calculation/Engineering.php | 136 +++++++++++++----- src/PhpSpreadsheet/Calculation/Logical.php | 58 ++++++-- src/PhpSpreadsheet/Calculation/MathTrig.php | 44 ++++-- .../Calculation/Statistical.php | 6 +- 4 files changed, 186 insertions(+), 58 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index d7ed6e31..f311fe99 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -17,7 +17,7 @@ class Engineering * * Parses a complex number into its real and imaginary parts, and an I or J suffix * - * @deprecated 2.0.0 No longer used by internal code. Please use the \Complex\Complex class instead + * @deprecated 1.12.0 No longer used by internal code. Please use the \Complex\Complex class instead * * @param string $complexNumber The complex number * @@ -43,7 +43,9 @@ class Engineering * Excel Function: * BESSELI(x,ord) * - * @Deprecated 2.0.0 Use the BESSELI() method in the Engineering\BesselI class instead + * @Deprecated 1.17.0 + * + * @see Use the BESSELI() method in the Engineering\BesselI class instead * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELI returns the #VALUE! error value. @@ -67,7 +69,9 @@ class Engineering * Excel Function: * BESSELJ(x,ord) * - * @Deprecated 2.0.0 Use the BESSELJ() method in the Engineering\BesselJ class instead + * @Deprecated 1.17.0 + * + * @see Use the BESSELJ() method in the Engineering\BesselJ class instead * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELJ returns the #VALUE! error value. @@ -91,7 +95,9 @@ class Engineering * Excel Function: * BESSELK(x,ord) * - * @Deprecated 2.0.0 Use the BESSELK() method in the Engineering\BesselK class instead + * @Deprecated 1.17.0 + * + * @see Use the BESSELK() method in the Engineering\BesselK class instead * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELK returns the #VALUE! error value. @@ -114,7 +120,9 @@ class Engineering * Excel Function: * BESSELY(x,ord) * - * @Deprecated 2.0.0 Use the BESSELY() method in the Engineering\BesselY class instead + * @Deprecated 1.17.0 + * + * @see Use the BESSELY() method in the Engineering\BesselY class instead * * @param float $x The value at which to evaluate the function. * If x is nonnumeric, BESSELY returns the #VALUE! error value. @@ -137,7 +145,9 @@ class Engineering * Excel Function: * BIN2DEC(x) * - * @Deprecated 2.0.0 Use the toDecimal() method in the Engineering\ConvertBinary class instead + * @Deprecated 1.17.0 + * + * @see Use the toDecimal() method in the Engineering\ConvertBinary class instead * * @param string $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant @@ -161,7 +171,9 @@ class Engineering * Excel Function: * BIN2HEX(x[,places]) * - * @Deprecated 2.0.0 Use the toHex() method in the Engineering\ConvertBinary class instead + * @Deprecated 1.17.0 + * + * @see Use the toHex() method in the Engineering\ConvertBinary class instead * * @param string $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant @@ -191,7 +203,9 @@ class Engineering * Excel Function: * BIN2OCT(x[,places]) * - * @Deprecated 2.0.0 Use the toOctal() method in the Engineering\ConvertBinary class instead + * @Deprecated 1.17.0 + * + * @see Use the toOctal() method in the Engineering\ConvertBinary class instead * * @param string $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant @@ -221,7 +235,9 @@ class Engineering * Excel Function: * DEC2BIN(x[,places]) * - * @Deprecated 2.0.0 Use the toBinary() method in the Engineering\ConvertDecimal class instead + * @Deprecated 1.17.0 + * + * @see Use the toBinary() method in the Engineering\ConvertDecimal class instead * * @param string $x The decimal integer you want to convert. If number is negative, * valid place values are ignored and DEC2BIN returns a 10-character @@ -255,7 +271,9 @@ class Engineering * Excel Function: * DEC2HEX(x[,places]) * - * @Deprecated 2.0.0 Use the toHex() method in the Engineering\ConvertDecimal class instead + * @Deprecated 1.17.0 + * + * @see Use the toHex() method in the Engineering\ConvertDecimal class instead * * @param string $x The decimal integer you want to convert. If number is negative, * places is ignored and DEC2HEX returns a 10-character (40-bit) @@ -289,7 +307,9 @@ class Engineering * Excel Function: * DEC2OCT(x[,places]) * - * @Deprecated 2.0.0 Use the toOctal() method in the Engineering\ConvertDecimal class instead + * @Deprecated 1.17.0 + * + * @see Use the toOctal() method in the Engineering\ConvertDecimal class instead * * @param string $x The decimal integer you want to convert. If number is negative, * places is ignored and DEC2OCT returns a 10-character (30-bit) @@ -323,7 +343,9 @@ class Engineering * Excel Function: * HEX2BIN(x[,places]) * - * @Deprecated 2.0.0 Use the toBinary() method in the Engineering\ConvertHex class instead + * @Deprecated 1.17.0 + * + * @see Use the toBinary() method in the Engineering\ConvertHex class instead * * @param string $x the hexadecimal number you want to convert. * Number cannot contain more than 10 characters. @@ -357,7 +379,9 @@ class Engineering * Excel Function: * HEX2DEC(x) * - * @Deprecated 2.0.0 Use the toDecimal() method in the Engineering\ConvertHex class instead + * @Deprecated 1.17.0 + * + * @see Use the toDecimal() method in the Engineering\ConvertHex class instead * * @param string $x The hexadecimal number you want to convert. This number cannot * contain more than 10 characters (40 bits). The most significant @@ -382,7 +406,9 @@ class Engineering * Excel Function: * HEX2OCT(x[,places]) * - * @Deprecated 2.0.0 Use the toOctal() method in the Engineering\ConvertHex class instead + * @Deprecated 1.17.0 + * + * @see Use the toOctal() method in the Engineering\ConvertHex class instead * * @param string $x The hexadecimal number you want to convert. Number cannot * contain more than 10 characters. The most significant bit of @@ -420,7 +446,9 @@ class Engineering * Excel Function: * OCT2BIN(x[,places]) * - * @Deprecated 2.0.0 Use the toBinary() method in the Engineering\ConvertOctal class instead + * @Deprecated 1.17.0 + * + * @see Use the toBinary() method in the Engineering\ConvertOctal class instead * * @param string $x The octal number you want to convert. Number may not * contain more than 10 characters. The most significant @@ -460,7 +488,9 @@ class Engineering * Excel Function: * OCT2DEC(x) * - * @Deprecated 2.0.0 Use the toDecimal() method in the Engineering\ConvertOctal class instead + * @Deprecated 1.17.0 + * + * @see Use the toDecimal() method in the Engineering\ConvertOctal class instead * * @param string $x The octal number you want to convert. Number may not contain * more than 10 octal characters (30 bits). The most significant @@ -485,7 +515,9 @@ class Engineering * Excel Function: * OCT2HEX(x[,places]) * - * @Deprecated 2.0.0 Use the toHex() method in the Engineering\ConvertOctal class instead + * @Deprecated 1.17.0 + * + * @see Use the toHex() method in the Engineering\ConvertOctal class instead * * @param string $x The octal number you want to convert. Number may not contain * more than 10 octal characters (30 bits). The most significant @@ -1098,7 +1130,9 @@ class Engineering * Excel Function: * DELTA(a[,b]) * - * @Deprecated 2.0.0 Use the DELTA() method in the Engineering\Compare class instead + * @Deprecated 1.17.0 + * + * @see Use the DELTA() method in the Engineering\Compare class instead * * @param float $a the first number * @param float $b The second number. If omitted, b is assumed to be zero. @@ -1120,7 +1154,9 @@ class Engineering * Use this function to filter a set of values. For example, by summing several GESTEP * functions you calculate the count of values that exceed a threshold. * - * @Deprecated 2.0.0 Use the GESTEP() method in the Engineering\Compare class instead + * @Deprecated 1.17.0 + * + * @see Use the GESTEP() method in the Engineering\Compare class instead * * @param float $number the value to test against step * @param float $step The threshold value. If you omit a value for step, GESTEP uses zero. @@ -1140,7 +1176,9 @@ class Engineering * Excel Function: * BITAND(number1, number2) * - * @Deprecated 2.0.0 Use the BITAND() method in the Engineering\BitWise class instead + * @Deprecated 1.17.0 + * + * @see Use the BITAND() method in the Engineering\BitWise class instead * * @param int $number1 * @param int $number2 @@ -1160,7 +1198,9 @@ class Engineering * Excel Function: * BITOR(number1, number2) * - * @Deprecated 2.0.0 Use the BITOR() method in the Engineering\BitWise class instead + * @Deprecated 1.17.0 + * + * @see Use the BITOR() method in the Engineering\BitWise class instead * * @param int $number1 * @param int $number2 @@ -1180,7 +1220,9 @@ class Engineering * Excel Function: * BITXOR(number1, number2) * - * @Deprecated 2.0.0 Use the BITXOR() method in the Engineering\BitWise class instead + * @Deprecated 1.17.0 + * + * @see Use the BITXOR() method in the Engineering\BitWise class instead * * @param int $number1 * @param int $number2 @@ -1200,7 +1242,9 @@ class Engineering * Excel Function: * BITLSHIFT(number, shift_amount) * - * @Deprecated 2.0.0 Use the BITLSHIFT() method in the Engineering\BitWise class instead + * @Deprecated 1.17.0 + * + * @see Use the BITLSHIFT() method in the Engineering\BitWise class instead * * @param int $number * @param int $shiftAmount @@ -1220,7 +1264,9 @@ class Engineering * Excel Function: * BITRSHIFT(number, shift_amount) * - * @Deprecated 2.0.0 Use the BITRSHIFT() method in the Engineering\BitWise class instead + * @Deprecated 1.17.0 + * + * @see Use the BITRSHIFT() method in the Engineering\BitWise class instead * * @param int $number * @param int $shiftAmount @@ -1245,7 +1291,9 @@ class Engineering * Excel Function: * ERF(lower[,upper]) * - * @Deprecated 2.0.0 Use the ERF() method in the Engineering\Erf class instead + * @Deprecated 1.17.0 + * + * @see Use the ERF() method in the Engineering\Erf class instead * * @param float $lower lower bound for integrating ERF * @param float $upper upper bound for integrating ERF. @@ -1266,7 +1314,9 @@ class Engineering * Excel Function: * ERF.PRECISE(limit) * - * @Deprecated 2.0.0 Use the ERFPRECISE() method in the Engineering\Erf class instead + * @Deprecated 1.17.0 + * + * @see Use the ERFPRECISE() method in the Engineering\Erf class instead * * @param float $limit bound for integrating ERF * @@ -1290,7 +1340,9 @@ class Engineering * Excel Function: * ERFC(x) * - * @Deprecated 2.0.0 Use the ERFC() method in the Engineering\ErfC class instead + * @Deprecated 1.17.0 + * + * @see Use the ERFC() method in the Engineering\ErfC class instead * * @param float $x The lower bound for integrating ERFC * @@ -1305,7 +1357,9 @@ class Engineering * getConversionGroups * Returns a list of the different conversion groups for UOM conversions. * - * @Deprecated 2.0.0 Use the getConversionCategories() method in the Engineering\ConvertUOM class instead + * @Deprecated 1.16.0 + * + * @see Use the getConversionCategories() method in the Engineering\ConvertUOM class instead * * @return array */ @@ -1318,7 +1372,9 @@ class Engineering * getConversionGroupUnits * Returns an array of units of measure, for a specified conversion group, or for all groups. * - * @Deprecated Use the getConversionCategoryUnits() method in the ConvertUOM class instead + * @Deprecated 1.16.0 + * + * @see Use the getConversionCategoryUnits() method in the ConvertUOM class instead * * @param null|mixed $category * @@ -1332,7 +1388,9 @@ class Engineering /** * getConversionGroupUnitDetails. * - * @Deprecated Use the getConversionCategoryUnitDetails() method in the ConvertUOM class instead + * @Deprecated 1.16.0 + * + * @see Use the getConversionCategoryUnitDetails() method in the ConvertUOM class instead * * @param null|mixed $category * @@ -1347,7 +1405,9 @@ class Engineering * getConversionMultipliers * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). * - * @Deprecated Use the getConversionMultipliers() method in the ConvertUOM class instead + * @Deprecated 1.16.0 + * + * @see Use the getConversionMultipliers() method in the ConvertUOM class instead * * @return array of mixed */ @@ -1357,10 +1417,14 @@ class Engineering } /** - * getBinaryConversionMultipliers - * Returns an array of the additional Multiplier prefixes that can be used with Information Units of Measure in CONVERTUOM(). + * getBinaryConversionMultipliers. * - * @Deprecated Use the getBinaryConversionMultipliers() method in the ConvertUOM class instead + * Returns an array of the additional Multiplier prefixes that can be used with Information Units of Measure + * in CONVERTUOM(). + * + * @Deprecated 1.16.0 + * + * @see Use the getBinaryConversionMultipliers() method in the ConvertUOM class instead * * @return array of mixed */ @@ -1379,7 +1443,9 @@ class Engineering * Excel Function: * CONVERT(value,fromUOM,toUOM) * - * @Deprecated Use the CONVERT() method in the ConvertUOM class instead + * @Deprecated 1.16.0 + * + * @see Use the CONVERT() method in the ConvertUOM class instead * * @param float|int $value the value in fromUOM to convert * @param string $fromUOM the units for value diff --git a/src/PhpSpreadsheet/Calculation/Logical.php b/src/PhpSpreadsheet/Calculation/Logical.php index 802ceb26..b267e1f0 100644 --- a/src/PhpSpreadsheet/Calculation/Logical.php +++ b/src/PhpSpreadsheet/Calculation/Logical.php @@ -4,6 +4,9 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Logical\Boolean; +/** + * @deprecated 1.17.0 + */ class Logical { /** @@ -14,7 +17,10 @@ class Logical * Excel Function: * =TRUE() * - * @Deprecated Use the TRUE() method in the Logical\Boolean class instead + * @Deprecated 1.17.0 + * + * @see Logical\Boolean::TRUE() + * Use the TRUE() method in the Logical\Boolean class instead * * @return bool True */ @@ -31,7 +37,10 @@ class Logical * Excel Function: * =FALSE() * - * @Deprecated Use the FALSE() method in the Logical\Boolean class instead + * @Deprecated 1.17.0 + * + * @see Logical\Boolean::FALSE() + * Use the FALSE() method in the Logical\Boolean class instead * * @return bool False */ @@ -56,7 +65,10 @@ class Logical * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value * - * @Deprecated Use the logicalAnd() method in the Logical\Operations class instead + * @Deprecated 1.17.0 + * + * @see Logical\Operations::logicalAnd() + * Use the logicalAnd() method in the Logical\Operations class instead * * @param mixed ...$args Data values * @@ -83,7 +95,10 @@ class Logical * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value * - * @Deprecated Use the logicalOr() method in the Logical\Operations class instead + * @Deprecated 1.17.0 + * + * @see Logical\Operations::logicalOr() + * Use the logicalOr() method in the Logical\Operations class instead * * @param mixed $args Data values * @@ -112,7 +127,10 @@ class Logical * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value * - * @Deprecated Use the logicalXor() method in the Logical\Operations class instead + * @Deprecated 1.17.0 + * + * @see Logical\Operations::logicalXor() + * Use the logicalXor() method in the Logical\Operations class instead * * @param mixed $args Data values * @@ -138,7 +156,10 @@ class Logical * If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string * holds the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value * - * @Deprecated Use the NOT() method in the Logical\Operations class instead + * @Deprecated 1.17.0 + * + * @see Logical\Operations::NOT() + * Use the NOT() method in the Logical\Operations class instead * * @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE * @@ -174,7 +195,10 @@ class Logical * If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned. * ReturnIfFalse can be another formula. * - * @Deprecated Use the statementIf() method in the Logical\Conditional class instead + * @Deprecated 1.17.0 + * + * @see Logical\Conditional::statementIf() + * Use the statementIf() method in the Logical\Conditional class instead * * @param mixed $condition Condition to evaluate * @param mixed $returnIfTrue Value to return when condition is true @@ -207,7 +231,10 @@ class Logical * Optional. It is the default to return if expression does not match any of the values * (value1, value2, ... value_n). * - * @Deprecated Use the statementSwitch() method in the Logical\Conditional class instead + * @Deprecated 1.17.0 + * + * @see Logical\Conditional::statementSwitch() + * Use the statementSwitch() method in the Logical\Conditional class instead * * @param mixed $arguments Statement arguments * @@ -224,7 +251,10 @@ class Logical * Excel Function: * =IFERROR(testValue,errorpart) * - * @Deprecated Use the IFERROR() method in the Logical\Conditional class instead + * @Deprecated 1.17.0 + * + * @see Logical\Conditional::IFERROR() + * Use the IFERROR() method in the Logical\Conditional class instead * * @param mixed $testValue Value to check, is also the value returned when no error * @param mixed $errorpart Value to return when testValue is an error condition @@ -242,7 +272,10 @@ class Logical * Excel Function: * =IFNA(testValue,napart) * - * @Deprecated Use the IFNA() method in the Logical\Conditional class instead + * @Deprecated 1.17.0 + * + * @see Logical\Conditional::IFNA() + * Use the IFNA() method in the Logical\Conditional class instead * * @param mixed $testValue Value to check, is also the value returned when not an NA * @param mixed $napart Value to return when testValue is an NA condition @@ -265,7 +298,10 @@ class Logical * returnIfTrue1 ... returnIfTrue_n * Value returned if corresponding testValue (nth) was true * - * @Deprecated Use the IFS() method in the Logical\Conditional class instead + * @Deprecated 1.17.0 + * + * @see Logical\Conditional::IFS() + * Use the IFS() method in the Logical\Conditional class instead * * @param mixed ...$arguments Statement arguments * diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index a4b335d1..0ba109f3 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -218,7 +218,9 @@ class MathTrig * Excel Function: * CEILING(number[,significance]) * - * @Deprecated 2.0.0 Use the funcCeiling method in the MathTrig\Ceiling class instead + * @Deprecated 1.17.0 + * + * @see Use the funcCeiling() method in the MathTrig\Ceiling class instead * * @param float $number the number you want to round * @param float $significance the multiple to which you want to round @@ -385,7 +387,9 @@ class MathTrig * Excel Function: * FLOOR(number[,significance]) * - * @Deprecated 2.0.0 Use the funcFloor method in the MathTrig\Floor class instead + * @Deprecated 1.17.0 + * + * @see Use the funcFloor() method in the MathTrig\Floor class instead * * @param float $number Number to round * @param float $significance Significance @@ -407,7 +411,9 @@ class MathTrig * Excel Function: * FLOOR.MATH(number[,significance[,mode]]) * - * @Deprecated 2.0.0 Use the funcFloorMath method in the MathTrig\FloorMath class instead + * @Deprecated 1.17.0 + * + * @see Use the funcFloorMath() method in the MathTrig\FloorMath class instead * * @param float $number Number to round * @param float $significance Significance @@ -430,7 +436,9 @@ class MathTrig * Excel Function: * FLOOR.PRECISE(number[,significance]) * - * @Deprecated 2.0.0 Use the funcFloorPrecise method in the MathTrig\FloorPrecise class instead + * @Deprecated 1.17.0 + * + * @see Use the funcFloorPrecise() method in the MathTrig\FloorPrecise class instead * * @param float $number Number to round * @param float $significance Significance @@ -457,7 +465,9 @@ class MathTrig * Excel Function: * INT(number) * - * @Deprecated 2.0.0 Use the funcInt method in the MathTrig\IntClass class instead + * @Deprecated 1.17.0 + * + * @see Use the funcInt() method in the MathTrig\IntClass class instead * * @param float $number Number to cast to an integer * @@ -779,7 +789,9 @@ class MathTrig * * Rounds a number to the nearest multiple of a specified value * - * @Deprecated 2.0.0 Use the funcMround method in the MathTrig\Mround class instead + * @Deprecated 1.17.0 + * + * @see Use the funcMround() method in the MathTrig\Mround class instead * * @param float $number Number to round * @param int $multiple Multiple to which you want to round $number @@ -995,7 +1007,9 @@ class MathTrig * * Converts a number to Roman numeral * - * @Deprecated 2.0.0 Use the funcRoman method in the MathTrig\Roman class instead + * @Deprecated 1.17.0 + * + * @see Use the funcRoman() method in the MathTrig\Roman class instead * * @param mixed $aValue Number to convert * @param mixed $style Number indicating one of five possible forms @@ -1014,7 +1028,9 @@ class MathTrig * * Rounds a number up to a specified number of decimal places * - * @Deprecated 2.0.0 Use the funcRoundUp method in the MathTrig\RoundUp class instead + * @Deprecated 1.17.0 + * + * @see Use the funcRoundUp() method in the MathTrig\RoundUp class instead * * @param float $number Number to round * @param int $digits Number of digits to which you want to round $number @@ -1033,7 +1049,9 @@ class MathTrig * * Rounds a number down to a specified number of decimal places * - * @Deprecated 2.0.0 Use the funcRoundDown method in the MathTrig\RoundDown class instead + * @Deprecated 1.17.0 + * + * @see Use the funcRoundDown() method in the MathTrig\RoundDown class instead * * @param float $number Number to round * @param int $digits Number of digits to which you want to round $number @@ -1517,7 +1535,9 @@ class MathTrig * * Truncates value to the number of fractional digits by number_digits. * - * @Deprecated 2.0.0 Use the funcTrunc method in the MathTrig\Trunc class instead + * @Deprecated 1.17.0 + * + * @see Use the funcTrunc() method in the MathTrig\Trunc class instead * * @param float $value * @param int $digits @@ -1722,7 +1742,9 @@ class MathTrig * * Returns the result of builtin function round after validating args. * - * @Deprecated 2.0.0 Use the builtinRound method in the MathTrig\Round class instead + * @Deprecated 1.17.0 + * + * @see Use the builtinRound() method in the MathTrig\Round class instead * * @param mixed $number Should be numeric * @param mixed $precision Should be int diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 5792b78f..f7d0c05f 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Permutations; use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend; class Statistical @@ -2923,7 +2924,10 @@ class Statistical * combinations, for which the internal order is not significant. Use this function * for lottery-style probability calculations. * - * @Deprecated 2.0.0 Use the PERMUT() method in the Statistical\Permutations class instead + * @Deprecated 1.17.0 + * + * @see Statistical\Permutations::PERMUT() + * Use the PERMUT() method in the Statistical\Permutations class instead * * @param int $numObjs Number of different objects * @param int $numInSet Number of objects in each permutation From 9909af6ccb9c48294eceedd7b5ebc7d16fa51b1e Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 14 Feb 2021 16:47:49 +0100 Subject: [PATCH 062/187] Fix coding standards issue --- src/PhpSpreadsheet/Reader/Xlsx.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 8d38fa3e..9a5e5e2d 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -719,7 +719,7 @@ class Xlsx extends BaseReader $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString'); if (isset($c->f['t'])) { $att = $c->f['t']; - $docSheet->getCell($r)->setFormulaAttributes(['t' => (string)$att]); + $docSheet->getCell($r)->setFormulaAttributes(['t' => (string) $att]); } } From 4e1f89d04c562c28786816f0e6d87d8507ec5733 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sun, 14 Feb 2021 17:12:01 +0100 Subject: [PATCH 063/187] Fix coding standards issue --- src/PhpSpreadsheet/Reader/Xlsx.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 1eab5ef3..2b37896d 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -722,8 +722,8 @@ class Xlsx extends BaseReader // Formula $this->castToFormula($c, $r, $cellDataType, $value, $calculatedValue, $sharedFormulas, 'castToString'); if (isset($c->f['t'])) { - $att = $c->f['t']; - $docSheet->getCell($r)->setFormulaAttributes(['t' => (string) $att]); + $attributes = $c->f['t']; + $docSheet->getCell($r)->setFormulaAttributes(['t' => (string) $attributes]); } } From ef3f8f30702f3f345c3df30c6ccc787f3cf3c841 Mon Sep 17 00:00:00 2001 From: oleibman Date: Sun, 14 Feb 2021 09:54:49 -0800 Subject: [PATCH 064/187] Use DateTime Rather than gmmktime in Sample Template (#1827) This avoids a potential Y2038 problem on 32-bit systems - see issue #1826. --- samples/templates/sampleSpreadsheet.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/templates/sampleSpreadsheet.php b/samples/templates/sampleSpreadsheet.php index 6d9568be..b698ba89 100644 --- a/samples/templates/sampleSpreadsheet.php +++ b/samples/templates/sampleSpreadsheet.php @@ -31,7 +31,9 @@ $spreadsheet->getProperties()->setCreator('Maarten Balliauw') $helper->log('Add some data'); $spreadsheet->setActiveSheetIndex(0); $spreadsheet->getActiveSheet()->setCellValue('B1', 'Invoice'); -$spreadsheet->getActiveSheet()->setCellValue('D1', Date::PHPToExcel(gmmktime(0, 0, 0, date('m'), date('d'), date('Y')))); +$date = new DateTime('now'); +$date->setTime(0, 0, 0); +$spreadsheet->getActiveSheet()->setCellValue('D1', Date::PHPToExcel($date)); $spreadsheet->getActiveSheet()->getStyle('D1')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_XLSX15); $spreadsheet->getActiveSheet()->setCellValue('E1', '#12566'); From 10c9c4cf23e5023bea64553fb8c302ea7c5359b5 Mon Sep 17 00:00:00 2001 From: oleibman Date: Mon, 15 Feb 2021 11:50:20 -0800 Subject: [PATCH 065/187] Make Documentation Updates Easier and More Accurate (#1573) I made a documentation change and noticed that the result when browsed locally did not quite match what is seen when browsing from the web. After some research, I found https://github.com/mkdocs/mkdocs/issues/2028 That described my situation well and suggested adding an extra javascript script to the configuration. This worked exactly as desired on my local machine. This accounts for the presence of extrajs.js and mkdocs.yml in this request. In addition to the display problem, "mkdocs build" generates the documentation into a directory which is not ignored by git. I added that directory to .gitignore as part of this request. Finally, since I don't know how exactly the documentation makes it to production, I made an insignificant change to one doc file as a sanity check. --- .gitignore | 3 +++ docs/extra/extrajs.js | 5 +++++ docs/index.md | 2 +- mkdocs.yml | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 docs/extra/extrajs.js diff --git a/.gitignore b/.gitignore index 0723541d..eac08567 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ *.project /.settings /.idea + +## mkdocs output +/site diff --git a/docs/extra/extrajs.js b/docs/extra/extrajs.js new file mode 100644 index 00000000..9ad135e8 --- /dev/null +++ b/docs/extra/extrajs.js @@ -0,0 +1,5 @@ +document.addEventListener("DOMContentLoaded", function() { + document.querySelectorAll("table").forEach(function(table) { + table.classList.add("docutils"); + }); +}); \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index b1207d53..42acedf9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -89,7 +89,7 @@ php vendor/phpoffice/phpspreadsheet/samples/Basic/01_Simple.php ## Learn by documentation -For more in-depth documentation, you may read about an [overview of the +For more documentation in depth, you may read about an [overview of the architecture](./topics/architecture.md), [creating a spreadsheet](./topics/creating-spreadsheet.md), [worksheets](./topics/worksheets.md), diff --git a/mkdocs.yml b/mkdocs.yml index cf87a142..f79acb69 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -5,3 +5,5 @@ edit_uri: edit/master/docs/ theme: readthedocs extra_css: - extra/extra.css +extra_javascript: + - extra/extrajs.js From 7c7b229041e770d9f0b4b19da654b4bcc9f2e633 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Thu, 18 Feb 2021 12:39:24 +0100 Subject: [PATCH 066/187] Let's see what Scrutinizer makes of these changes (#1859) * Let's see what Scrutinizer makes of these changes --- src/PhpSpreadsheet/Calculation/Database.php | 2 +- src/PhpSpreadsheet/Calculation/Financial.php | 12 +++--- src/PhpSpreadsheet/Calculation/MathTrig.php | 4 +- src/PhpSpreadsheet/Chart/Axis.php | 12 +++--- src/PhpSpreadsheet/Chart/GridLines.php | 4 +- src/PhpSpreadsheet/Helper/Html.php | 2 +- src/PhpSpreadsheet/Reader/Gnumeric.php | 4 +- src/PhpSpreadsheet/Reader/Slk.php | 6 +-- src/PhpSpreadsheet/Reader/Xls.php | 3 +- src/PhpSpreadsheet/Reader/Xlsx.php | 2 +- src/PhpSpreadsheet/Reader/Xml.php | 4 +- src/PhpSpreadsheet/Style/Style.php | 14 ++++--- src/PhpSpreadsheet/Worksheet/CellIterator.php | 8 +--- src/PhpSpreadsheet/Worksheet/Column.php | 4 +- .../Worksheet/ColumnCellIterator.php | 19 ++++------ .../Worksheet/ColumnDimension.php | 30 +++++---------- .../Worksheet/ColumnIterator.php | 22 +++++------ src/PhpSpreadsheet/Worksheet/Dimension.php | 38 ++++++------------- src/PhpSpreadsheet/Worksheet/Iterator.php | 8 +--- src/PhpSpreadsheet/Worksheet/Row.php | 8 +--- .../Worksheet/RowCellIterator.php | 19 ++++------ src/PhpSpreadsheet/Worksheet/RowDimension.php | 24 ++++-------- src/PhpSpreadsheet/Worksheet/RowIterator.php | 18 ++++----- src/PhpSpreadsheet/Writer/Xls/Worksheet.php | 4 +- .../Functions/MathTrig/SubTotalTest.php | 12 +++--- .../Worksheet/ColumnCellIterator2Test.php | 8 ++-- .../Worksheet/ColumnIteratorTest.php | 24 ++++++++++++ .../Worksheet/RowCellIterator2Test.php | 8 ++-- .../Worksheet/RowIteratorTest.php | 24 ++++++++++++ .../Calculation/MathTrig/SUBTOTALHIDDEN.php | 26 +++++++++++++ 30 files changed, 197 insertions(+), 176 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Database.php b/src/PhpSpreadsheet/Calculation/Database.php index 2ba4af2d..5250e306 100644 --- a/src/PhpSpreadsheet/Calculation/Database.php +++ b/src/PhpSpreadsheet/Calculation/Database.php @@ -33,7 +33,7 @@ class Database } $key = array_search($field, $fieldNames); - return ($key) ? $key : null; + return $key ?: null; } /** diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 3c24eb3b..f0b5ab05 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -2270,7 +2270,7 @@ class Financial // create an initial range, with a root somewhere between 0 and guess $guess = Functions::flattenSingleValue($guess); $x1 = 0.0; - $x2 = $guess ? $guess : 0.1; + $x2 = $guess ?: 0.1; $f1 = self::xnpvOrdered($x1, $values, $dates, false); $f2 = self::xnpvOrdered($x2, $values, $dates, false); $found = false; @@ -2306,12 +2306,12 @@ class Financial * * @param float $rate the discount rate to apply to the cash flows * @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates. - * The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. - * If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. - * The series of values must contain at least one positive value and one negative value. + * The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. + * If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. + * The series of values must contain at least one positive value and one negative value. * @param mixed[] $dates A schedule of payment dates that corresponds to the cash flow payments. - * The first payment date indicates the beginning of the schedule of payments. - * All other dates must be later than this date, but they may occur in any order. + * The first payment date indicates the beginning of the schedule of payments. + * All other dates must be later than this date, but they may occur in any order. * * @return float|mixed|string */ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 0ba109f3..e62e9497 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -146,8 +146,8 @@ class MathTrig $xCoordinate = Functions::flattenSingleValue($xCoordinate); $yCoordinate = Functions::flattenSingleValue($yCoordinate); - $xCoordinate = ($xCoordinate !== null) ? $xCoordinate : 0.0; - $yCoordinate = ($yCoordinate !== null) ? $yCoordinate : 0.0; + $xCoordinate = $xCoordinate ?? 0.0; + $yCoordinate = $yCoordinate ?? 0.0; if ( ((is_numeric($xCoordinate)) || (is_bool($xCoordinate))) && diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php index 7995c3b3..455a5faa 100644 --- a/src/PhpSpreadsheet/Chart/Axis.php +++ b/src/PhpSpreadsheet/Chart/Axis.php @@ -340,9 +340,9 @@ class Axis extends Properties { $this->setShadowPresetsProperties((int) $sh_presets) ->setShadowColor( - $sh_color_value === null ? $this->shadowProperties['color']['value'] : $sh_color_value, - $sh_color_alpha === null ? (int) $this->shadowProperties['color']['alpha'] : $sh_color_alpha, - $sh_color_type === null ? $this->shadowProperties['color']['type'] : $sh_color_type + $sh_color_value ?? $this->shadowProperties['color']['value'], + $sh_color_alpha ?? (int) $this->shadowProperties['color']['alpha'], + $sh_color_type ?? $this->shadowProperties['color']['type'] ) ->setShadowBlur($sh_blur) ->setShadowAngle($sh_angle) @@ -482,9 +482,9 @@ class Axis extends Properties { $this->setGlowSize($size) ->setGlowColor( - $color_value === null ? $this->glowProperties['color']['value'] : $color_value, - $color_alpha === null ? (int) $this->glowProperties['color']['alpha'] : $color_alpha, - $color_type === null ? $this->glowProperties['color']['type'] : $color_type + $color_value ?? $this->glowProperties['color']['value'], + $color_alpha ?? (int) $this->glowProperties['color']['alpha'], + $color_type ?? $this->glowProperties['color']['type'] ); } diff --git a/src/PhpSpreadsheet/Chart/GridLines.php b/src/PhpSpreadsheet/Chart/GridLines.php index 2e424bc2..385b278b 100644 --- a/src/PhpSpreadsheet/Chart/GridLines.php +++ b/src/PhpSpreadsheet/Chart/GridLines.php @@ -291,9 +291,9 @@ class GridLines extends Properties $this->activateObject() ->setShadowPresetsProperties((int) $sh_presets) ->setShadowColor( - $sh_color_value === null ? $this->shadowProperties['color']['value'] : $sh_color_value, + $sh_color_value ?? $this->shadowProperties['color']['value'], $sh_color_alpha === null ? (int) $this->shadowProperties['color']['alpha'] : $this->getTrueAlpha($sh_color_alpha), - $sh_color_type === null ? $this->shadowProperties['color']['type'] : $sh_color_type + $sh_color_type ?? $this->shadowProperties['color']['type'] ) ->setShadowBlur($sh_blur) ->setShadowAngle($sh_angle) diff --git a/src/PhpSpreadsheet/Helper/Html.php b/src/PhpSpreadsheet/Helper/Html.php index 6c4cbf9b..f07bc961 100644 --- a/src/PhpSpreadsheet/Helper/Html.php +++ b/src/PhpSpreadsheet/Helper/Html.php @@ -711,7 +711,7 @@ class Html } elseif (strpos(trim($attributeValue), '#') === 0) { $this->$attributeName = ltrim($attributeValue, '#'); } else { - $this->$attributeName = $this->colourNameLookup($attributeValue); + $this->$attributeName = static::colourNameLookup($attributeValue); } } else { $this->$attributeName = $attributeValue; diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index dc921c1e..2bec2a13 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -657,7 +657,7 @@ class Gnumeric extends BaseReader $column = $columnAttributes['No']; $columnWidth = ((float) $columnAttributes['Unit']) / 5.4; $hidden = (isset($columnAttributes['Hidden'])) && ((string) $columnAttributes['Hidden'] == '1'); - $columnCount = (isset($columnAttributes['Count'])) ? $columnAttributes['Count'] : 1; + $columnCount = $columnAttributes['Count'] ?? 1; while ($c < $column) { $this->spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($defaultWidth); ++$c; @@ -696,7 +696,7 @@ class Gnumeric extends BaseReader $row = $rowAttributes['No']; $rowHeight = (float) $rowAttributes['Unit']; $hidden = (isset($rowAttributes['Hidden'])) && ((string) $rowAttributes['Hidden'] == '1'); - $rowCount = (isset($rowAttributes['Count'])) ? $rowAttributes['Count'] : 1; + $rowCount = $rowAttributes['Count'] ?? 1; while ($r < $row) { ++$r; $this->spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight); diff --git a/src/PhpSpreadsheet/Reader/Slk.php b/src/PhpSpreadsheet/Reader/Slk.php index e58ff2f6..89d80ffa 100644 --- a/src/PhpSpreadsheet/Reader/Slk.php +++ b/src/PhpSpreadsheet/Reader/Slk.php @@ -419,14 +419,14 @@ class Slk extends BaseReader if ($columnWidth > '') { if ($startCol == $endCol) { $startCol = Coordinate::stringFromColumnIndex((int) $startCol); - $spreadsheet->getActiveSheet()->getColumnDimension($startCol)->setWidth($columnWidth); + $spreadsheet->getActiveSheet()->getColumnDimension($startCol)->setWidth((float) $columnWidth); } else { $startCol = Coordinate::stringFromColumnIndex($startCol); $endCol = Coordinate::stringFromColumnIndex($endCol); $spreadsheet->getActiveSheet()->getColumnDimension($startCol)->setWidth((float) $columnWidth); do { - $spreadsheet->getActiveSheet()->getColumnDimension(++$startCol)->setWidth($columnWidth); - } while ($startCol != $endCol); + $spreadsheet->getActiveSheet()->getColumnDimension(++$startCol)->setWidth((float) $columnWidth); + } while ($startCol !== $endCol); } } } diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 5656a0ff..6d6b87fd 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -1703,7 +1703,8 @@ class Xls extends BaseReader // max 2048 bytes will probably throw a wobbly. $row = self::getUInt2d($recordData, 0); $extension = true; - $cellAddress = array_pop(array_keys($this->phpSheet->getComments())); + $arrayKeys = array_keys($this->phpSheet->getComments()); + $cellAddress = array_pop($arrayKeys); } $cellAddress = str_replace('$', '', $cellAddress); diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 2b37896d..bf754591 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -516,7 +516,7 @@ class Xlsx extends BaseReader } $style = (object) [ - 'numFmt' => $numFmt === null ? NumberFormat::FORMAT_GENERAL : $numFmt, + 'numFmt' => $numFmt ?? NumberFormat::FORMAT_GENERAL, 'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])], 'fill' => $xmlStyles->fills->fill[(int) ($xf['fillId'])], 'border' => $xmlStyles->borders->border[(int) ($xf['borderId'])], diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index 9de88233..f38a9515 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -421,7 +421,7 @@ class Xml extends BaseReader $xml_ss = $xml->children($namespaces['ss']); foreach ($xml_ss->Worksheet as $worksheetx) { - $worksheet = ($worksheetx === null) ? new SimpleXMLElement('') : $worksheetx; + $worksheet = $worksheetx ?? new SimpleXMLElement(''); $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); if ( @@ -665,7 +665,7 @@ class Xml extends BaseReader foreach ($xml->Styles[0] as $style) { $style_ss = self::getAttributes($style, $namespaces['ss']); $styleID = (string) $style_ss['ID']; - $this->styles[$styleID] = (isset($this->styles['Default'])) ? $this->styles['Default'] : []; + $this->styles[$styleID] = $this->styles['Default'] ?? []; foreach ($style as $styleType => $styleDatax) { $styleData = $styleDatax ?? new SimpleXMLElement(''); $styleAttributes = $styleData->attributes($namespaces['ss']); diff --git a/src/PhpSpreadsheet/Style/Style.php b/src/PhpSpreadsheet/Style/Style.php index f7c1be23..7fec9a00 100644 --- a/src/PhpSpreadsheet/Style/Style.php +++ b/src/PhpSpreadsheet/Style/Style.php @@ -359,7 +359,9 @@ class Style extends Supervisor $cellIterator = $columnIterator->getCellIterator(); $cellIterator->setIterateOnlyExistingCells(true); foreach ($cellIterator as $columnCell) { - $columnCell->getStyle()->applyFromArray($pStyles); + if ($columnCell !== null) { + $columnCell->getStyle()->applyFromArray($pStyles); + } } } @@ -367,7 +369,7 @@ class Style extends Supervisor case 'ROW': $oldXfIndexes = []; for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { - if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() == null) { + if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() === null) { $oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style } else { $oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true; @@ -377,7 +379,9 @@ class Style extends Supervisor $cellIterator = $rowIterator->getCellIterator(); $cellIterator->setIterateOnlyExistingCells(true); foreach ($cellIterator as $rowCell) { - $rowCell->getStyle()->applyFromArray($pStyles); + if ($rowCell !== null) { + $rowCell->getStyle()->applyFromArray($pStyles); + } } } @@ -423,8 +427,8 @@ class Style extends Supervisor case 'ROW': for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { $rowDimension = $this->getActiveSheet()->getRowDimension($row); - $oldXfIndex = $rowDimension->getXfIndex() === null ? - 0 : $rowDimension->getXfIndex(); // row without explicit style should be formatted based on default style + // row without explicit style should be formatted based on default style + $oldXfIndex = $rowDimension->getXfIndex() ?? 0; $rowDimension->setXfIndex($newXfIndexes[$oldXfIndex]); } diff --git a/src/PhpSpreadsheet/Worksheet/CellIterator.php b/src/PhpSpreadsheet/Worksheet/CellIterator.php index 45f76cab..e0f35b64 100644 --- a/src/PhpSpreadsheet/Worksheet/CellIterator.php +++ b/src/PhpSpreadsheet/Worksheet/CellIterator.php @@ -30,10 +30,8 @@ abstract class CellIterator implements Iterator /** * Get loop only existing cells. - * - * @return bool */ - public function getIterateOnlyExistingCells() + public function getIterateOnlyExistingCells(): bool { return $this->onlyExistingCells; } @@ -45,10 +43,8 @@ abstract class CellIterator implements Iterator /** * Set the iterator to loop only existing cells. - * - * @param bool $value */ - public function setIterateOnlyExistingCells($value): void + public function setIterateOnlyExistingCells(bool $value): void { $this->onlyExistingCells = (bool) $value; diff --git a/src/PhpSpreadsheet/Worksheet/Column.php b/src/PhpSpreadsheet/Worksheet/Column.php index 410e8073..763806a0 100644 --- a/src/PhpSpreadsheet/Worksheet/Column.php +++ b/src/PhpSpreadsheet/Worksheet/Column.php @@ -41,10 +41,8 @@ class Column /** * Get column index as string eg: 'A'. - * - * @return string */ - public function getColumnIndex() + public function getColumnIndex(): string { return $this->columnIndex; } diff --git a/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php b/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php index 714ee7ce..1390214e 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet; +use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; @@ -59,7 +60,7 @@ class ColumnCellIterator extends CellIterator * * @return $this */ - public function resetStart($startRow = 1) + public function resetStart(int $startRow = 1) { $this->startRow = $startRow; $this->adjustForExistingOnlyRange(); @@ -77,7 +78,7 @@ class ColumnCellIterator extends CellIterator */ public function resetEnd($endRow = null) { - $this->endRow = ($endRow) ? $endRow : $this->worksheet->getHighestRow(); + $this->endRow = $endRow ?: $this->worksheet->getHighestRow(); $this->adjustForExistingOnlyRange(); return $this; @@ -90,7 +91,7 @@ class ColumnCellIterator extends CellIterator * * @return $this */ - public function seek($row = 1) + public function seek(int $row = 1) { if ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) { throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist'); @@ -113,20 +114,16 @@ class ColumnCellIterator extends CellIterator /** * Return the current cell in this worksheet column. - * - * @return \PhpOffice\PhpSpreadsheet\Cell\Cell */ - public function current() + public function current(): ?Cell { return $this->worksheet->getCellByColumnAndRow($this->columnIndex, $this->currentRow); } /** * Return the current iterator key. - * - * @return int */ - public function key() + public function key(): int { return $this->currentRow; } @@ -161,10 +158,8 @@ class ColumnCellIterator extends CellIterator /** * Indicate if more rows exist in the worksheet range of rows that we're iterating. - * - * @return bool */ - public function valid() + public function valid(): bool { return $this->currentRow <= $this->endRow && $this->currentRow >= $this->startRow; } diff --git a/src/PhpSpreadsheet/Worksheet/ColumnDimension.php b/src/PhpSpreadsheet/Worksheet/ColumnDimension.php index 4e87a344..12b1efdf 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnDimension.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnDimension.php @@ -43,10 +43,8 @@ class ColumnDimension extends Dimension /** * Get column index as string eg: 'A'. - * - * @return string */ - public function getColumnIndex() + public function getColumnIndex(): string { return $this->columnIndex; } @@ -54,23 +52,19 @@ class ColumnDimension extends Dimension /** * Set column index as string eg: 'A'. * - * @param string $pValue - * * @return $this */ - public function setColumnIndex($pValue) + public function setColumnIndex(string $index) { - $this->columnIndex = $pValue; + $this->columnIndex = $index; return $this; } /** * Get Width. - * - * @return float */ - public function getWidth() + public function getWidth(): float { return $this->width; } @@ -78,23 +72,19 @@ class ColumnDimension extends Dimension /** * Set Width. * - * @param float $pValue - * * @return $this */ - public function setWidth($pValue) + public function setWidth(float $width) { - $this->width = $pValue; + $this->width = $width; return $this; } /** * Get Auto Size. - * - * @return bool */ - public function getAutoSize() + public function getAutoSize(): bool { return $this->autoSize; } @@ -102,13 +92,11 @@ class ColumnDimension extends Dimension /** * Set Auto Size. * - * @param bool $pValue - * * @return $this */ - public function setAutoSize($pValue) + public function setAutoSize(bool $autosizeEnabled) { - $this->autoSize = $pValue; + $this->autoSize = $autosizeEnabled; return $this; } diff --git a/src/PhpSpreadsheet/Worksheet/ColumnIterator.php b/src/PhpSpreadsheet/Worksheet/ColumnIterator.php index d0bb20cc..a7466881 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnIterator.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnIterator.php @@ -67,11 +67,13 @@ class ColumnIterator implements Iterator * * @return $this */ - public function resetStart($startColumn = 'A') + public function resetStart(string $startColumn = 'A') { $startColumnIndex = Coordinate::columnIndexFromString($startColumn); if ($startColumnIndex > Coordinate::columnIndexFromString($this->worksheet->getHighestColumn())) { - throw new Exception("Start column ({$startColumn}) is beyond highest column ({$this->worksheet->getHighestColumn()})"); + throw new Exception( + "Start column ({$startColumn}) is beyond highest column ({$this->worksheet->getHighestColumn()})" + ); } $this->startColumnIndex = $startColumnIndex; @@ -92,7 +94,7 @@ class ColumnIterator implements Iterator */ public function resetEnd($endColumn = null) { - $endColumn = $endColumn ? $endColumn : $this->worksheet->getHighestColumn(); + $endColumn = $endColumn ?: $this->worksheet->getHighestColumn(); $this->endColumnIndex = Coordinate::columnIndexFromString($endColumn); return $this; @@ -105,11 +107,13 @@ class ColumnIterator implements Iterator * * @return $this */ - public function seek($column = 'A') + public function seek(string $column = 'A') { $column = Coordinate::columnIndexFromString($column); if (($column < $this->startColumnIndex) || ($column > $this->endColumnIndex)) { - throw new PhpSpreadsheetException("Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})"); + throw new PhpSpreadsheetException( + "Column $column is out of range ({$this->startColumnIndex} - {$this->endColumnIndex})" + ); } $this->currentColumnIndex = $column; @@ -136,10 +140,8 @@ class ColumnIterator implements Iterator /** * Return the current iterator key. - * - * @return string */ - public function key() + public function key(): string { return Coordinate::stringFromColumnIndex($this->currentColumnIndex); } @@ -162,10 +164,8 @@ class ColumnIterator implements Iterator /** * Indicate if more columns exist in the worksheet range of columns that we're iterating. - * - * @return bool */ - public function valid() + public function valid(): bool { return $this->currentColumnIndex <= $this->endColumnIndex && $this->currentColumnIndex >= $this->startColumnIndex; } diff --git a/src/PhpSpreadsheet/Worksheet/Dimension.php b/src/PhpSpreadsheet/Worksheet/Dimension.php index a27daf09..4b3a0da8 100644 --- a/src/PhpSpreadsheet/Worksheet/Dimension.php +++ b/src/PhpSpreadsheet/Worksheet/Dimension.php @@ -47,10 +47,8 @@ abstract class Dimension /** * Get Visible. - * - * @return bool */ - public function getVisible() + public function getVisible(): bool { return $this->visible; } @@ -58,23 +56,19 @@ abstract class Dimension /** * Set Visible. * - * @param bool $pValue - * * @return $this */ - public function setVisible($pValue) + public function setVisible(bool $visible) { - $this->visible = (bool) $pValue; + $this->visible = $visible; return $this; } /** * Get Outline Level. - * - * @return int */ - public function getOutlineLevel() + public function getOutlineLevel(): int { return $this->outlineLevel; } @@ -83,27 +77,23 @@ abstract class Dimension * Set Outline Level. * Value must be between 0 and 7. * - * @param int $pValue - * * @return $this */ - public function setOutlineLevel($pValue) + public function setOutlineLevel(int $level) { - if ($pValue < 0 || $pValue > 7) { + if ($level < 0 || $level > 7) { throw new PhpSpreadsheetException('Outline level must range between 0 and 7.'); } - $this->outlineLevel = $pValue; + $this->outlineLevel = $level; return $this; } /** * Get Collapsed. - * - * @return bool */ - public function getCollapsed() + public function getCollapsed(): bool { return $this->collapsed; } @@ -111,13 +101,11 @@ abstract class Dimension /** * Set Collapsed. * - * @param bool $pValue - * * @return $this */ - public function setCollapsed($pValue) + public function setCollapsed(bool $collapsed) { - $this->collapsed = (bool) $pValue; + $this->collapsed = $collapsed; return $this; } @@ -127,7 +115,7 @@ abstract class Dimension * * @return int */ - public function getXfIndex() + public function getXfIndex(): ?int { return $this->xfIndex; } @@ -135,11 +123,9 @@ abstract class Dimension /** * Set index to cellXf. * - * @param int $pValue - * * @return $this */ - public function setXfIndex($pValue) + public function setXfIndex(int $pValue) { $this->xfIndex = $pValue; diff --git a/src/PhpSpreadsheet/Worksheet/Iterator.php b/src/PhpSpreadsheet/Worksheet/Iterator.php index 6cfed37a..93b0bb04 100644 --- a/src/PhpSpreadsheet/Worksheet/Iterator.php +++ b/src/PhpSpreadsheet/Worksheet/Iterator.php @@ -47,20 +47,16 @@ class Iterator implements \Iterator /** * Current Worksheet. - * - * @return Worksheet */ - public function current() + public function current(): Worksheet { return $this->subject->getSheet($this->position); } /** * Current key. - * - * @return int */ - public function key() + public function key(): int { return $this->position; } diff --git a/src/PhpSpreadsheet/Worksheet/Row.php b/src/PhpSpreadsheet/Worksheet/Row.php index 4f48a346..cf935743 100644 --- a/src/PhpSpreadsheet/Worksheet/Row.php +++ b/src/PhpSpreadsheet/Worksheet/Row.php @@ -41,10 +41,8 @@ class Row /** * Get row index. - * - * @return int */ - public function getRowIndex() + public function getRowIndex(): int { return $this->rowIndex; } @@ -64,10 +62,8 @@ class Row /** * Returns bound worksheet. - * - * @return Worksheet */ - public function getWorksheet() + public function getWorksheet(): Worksheet { return $this->worksheet; } diff --git a/src/PhpSpreadsheet/Worksheet/RowCellIterator.php b/src/PhpSpreadsheet/Worksheet/RowCellIterator.php index 9b9d54eb..6a96a826 100644 --- a/src/PhpSpreadsheet/Worksheet/RowCellIterator.php +++ b/src/PhpSpreadsheet/Worksheet/RowCellIterator.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet; +use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; @@ -59,7 +60,7 @@ class RowCellIterator extends CellIterator * * @return $this */ - public function resetStart($startColumn = 'A') + public function resetStart(string $startColumn = 'A') { $this->startColumnIndex = Coordinate::columnIndexFromString($startColumn); $this->adjustForExistingOnlyRange(); @@ -77,7 +78,7 @@ class RowCellIterator extends CellIterator */ public function resetEnd($endColumn = null) { - $endColumn = $endColumn ? $endColumn : $this->worksheet->getHighestColumn(); + $endColumn = $endColumn ?: $this->worksheet->getHighestColumn(); $this->endColumnIndex = Coordinate::columnIndexFromString($endColumn); $this->adjustForExistingOnlyRange(); @@ -91,7 +92,7 @@ class RowCellIterator extends CellIterator * * @return $this */ - public function seek($column = 'A') + public function seek(string $column = 'A') { $columnx = $column; $column = Coordinate::columnIndexFromString($column); @@ -116,20 +117,16 @@ class RowCellIterator extends CellIterator /** * Return the current cell in this worksheet row. - * - * @return \PhpOffice\PhpSpreadsheet\Cell\Cell */ - public function current() + public function current(): ?Cell { return $this->worksheet->getCellByColumnAndRow($this->currentColumnIndex, $this->rowIndex); } /** * Return the current iterator key. - * - * @return string */ - public function key() + public function key(): string { return Coordinate::stringFromColumnIndex($this->currentColumnIndex); } @@ -166,10 +163,8 @@ class RowCellIterator extends CellIterator /** * Return the current iterator position. - * - * @return int */ - public function getCurrentColumnIndex() + public function getCurrentColumnIndex(): int { return $this->currentColumnIndex; } diff --git a/src/PhpSpreadsheet/Worksheet/RowDimension.php b/src/PhpSpreadsheet/Worksheet/RowDimension.php index c4a87bdb..d86dd80f 100644 --- a/src/PhpSpreadsheet/Worksheet/RowDimension.php +++ b/src/PhpSpreadsheet/Worksheet/RowDimension.php @@ -43,10 +43,8 @@ class RowDimension extends Dimension /** * Get Row Index. - * - * @return int */ - public function getRowIndex() + public function getRowIndex(): int { return $this->rowIndex; } @@ -54,13 +52,11 @@ class RowDimension extends Dimension /** * Set Row Index. * - * @param int $pValue - * * @return $this */ - public function setRowIndex($pValue) + public function setRowIndex(int $index) { - $this->rowIndex = $pValue; + $this->rowIndex = $index; return $this; } @@ -78,23 +74,21 @@ class RowDimension extends Dimension /** * Set Row Height. * - * @param float $pValue + * @param float $height * * @return $this */ - public function setRowHeight($pValue) + public function setRowHeight($height) { - $this->height = $pValue; + $this->height = $height; return $this; } /** * Get ZeroHeight. - * - * @return bool */ - public function getZeroHeight() + public function getZeroHeight(): bool { return $this->zeroHeight; } @@ -102,11 +96,9 @@ class RowDimension extends Dimension /** * Set ZeroHeight. * - * @param bool $pValue - * * @return $this */ - public function setZeroHeight($pValue) + public function setZeroHeight(bool $pValue) { $this->zeroHeight = $pValue; diff --git a/src/PhpSpreadsheet/Worksheet/RowIterator.php b/src/PhpSpreadsheet/Worksheet/RowIterator.php index 42542533..469c284c 100644 --- a/src/PhpSpreadsheet/Worksheet/RowIterator.php +++ b/src/PhpSpreadsheet/Worksheet/RowIterator.php @@ -65,10 +65,12 @@ class RowIterator implements Iterator * * @return $this */ - public function resetStart($startRow = 1) + public function resetStart(int $startRow = 1) { if ($startRow > $this->subject->getHighestRow()) { - throw new PhpSpreadsheetException("Start row ({$startRow}) is beyond highest row ({$this->subject->getHighestRow()})"); + throw new PhpSpreadsheetException( + "Start row ({$startRow}) is beyond highest row ({$this->subject->getHighestRow()})" + ); } $this->startRow = $startRow; @@ -89,7 +91,7 @@ class RowIterator implements Iterator */ public function resetEnd($endRow = null) { - $this->endRow = ($endRow) ? $endRow : $this->subject->getHighestRow(); + $this->endRow = $endRow ?: $this->subject->getHighestRow(); return $this; } @@ -101,7 +103,7 @@ class RowIterator implements Iterator * * @return $this */ - public function seek($row = 1) + public function seek(int $row = 1) { if (($row < $this->startRow) || ($row > $this->endRow)) { throw new PhpSpreadsheetException("Row $row is out of range ({$this->startRow} - {$this->endRow})"); @@ -131,10 +133,8 @@ class RowIterator implements Iterator /** * Return the current iterator key. - * - * @return int */ - public function key() + public function key(): int { return $this->position; } @@ -157,10 +157,8 @@ class RowIterator implements Iterator /** * Indicate if more rows exist in the worksheet range of rows that we're iterating. - * - * @return bool */ - public function valid() + public function valid(): bool { return $this->position <= $this->endRow && $this->position >= $this->startRow; } diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php index a793128a..d2784d6d 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php @@ -1715,9 +1715,7 @@ class Worksheet extends BIFFwriter $length = 0x0022; // Number of bytes to follow $iPaperSize = $this->phpSheet->getPageSetup()->getPaperSize(); // Paper size - - $iScale = $this->phpSheet->getPageSetup()->getScale() ? - $this->phpSheet->getPageSetup()->getScale() : 100; // Print scaling factor + $iScale = $this->phpSheet->getPageSetup()->getScale() ?: 100; // Print scaling factor $iPageStart = 0x01; // Starting page number $iFitWidth = (int) $this->phpSheet->getPageSetup()->getFitToWidth(); // Fit to number of pages wide diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php index 14865673..efee60bd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php @@ -57,11 +57,10 @@ class SubTotalTest extends TestCase return require 'tests/data/Calculation/MathTrig/SUBTOTAL.php'; } - protected function rowVisibility() + protected function rowVisibility($data) { - $data = [1 => false, 2 => true, 3 => false, 4 => true, 5 => false, 6 => false, 7 => false, 8 => true, 9 => false, 10 => true, 11 => true]; - foreach ($data as $k => $v) { - yield $k => $v; + foreach ($data as $row => $visibility) { + yield $row => $visibility; } } @@ -69,10 +68,11 @@ class SubTotalTest extends TestCase * @dataProvider providerHiddenSUBTOTAL * * @param mixed $expectedResult + * @param mixed $hiddenRows */ - public function testHiddenSUBTOTAL($expectedResult, ...$args): void + public function testHiddenSUBTOTAL($expectedResult, $hiddenRows, ...$args): void { - $visibilityGenerator = $this->rowVisibility(); + $visibilityGenerator = $this->rowVisibility($hiddenRows); $rowDimension = $this->getMockBuilder(RowDimension::class) ->setMethods(['getVisible']) diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php index c542d89e..90280bd2 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php @@ -25,9 +25,11 @@ class ColumnCellIterator2Test extends TestCase $lastCoordinate = ''; $firstCoordinate = ''; foreach ($iterator as $cell) { - $lastCoordinate = $cell->getCoordinate(); - if (!$firstCoordinate) { - $firstCoordinate = $lastCoordinate; + if ($cell !== null) { + $lastCoordinate = $cell->getCoordinate(); + if (!$firstCoordinate) { + $firstCoordinate = $lastCoordinate; + } } } self::assertEquals($expectedResultFirst, $firstCoordinate); diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php index de985cee..71a05d48 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php @@ -67,6 +67,22 @@ class ColumnIteratorTest extends TestCase } } + public function testIteratorResetStart(): void + { + $iterator = new ColumnIterator($this->mockWorksheet, 'B', 'D'); + $iterator->resetStart('E'); + + $key = $iterator->key(); + self::assertSame('E', $key); + + $lastColumn = $iterator->key(); + while ($iterator->valid() !== false) { + $iterator->next(); + $lastColumn = $iterator->key(); + } + self::assertSame('F', $lastColumn); + } + public function testSeekOutOfRange(): void { $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); @@ -81,4 +97,12 @@ class ColumnIteratorTest extends TestCase $iterator->prev(); self::assertFalse($iterator->valid()); } + + public function testResetStartOutOfRange(): void + { + $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + + $iterator = new ColumnIterator($this->mockWorksheet, 'B', 'D'); + $iterator->resetStart('H'); + } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php b/tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php index 20d10da9..52183168 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php +++ b/tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php @@ -25,9 +25,11 @@ class RowCellIterator2Test extends TestCase $lastCoordinate = ''; $firstCoordinate = ''; foreach ($iterator as $cell) { - $lastCoordinate = $cell->getCoordinate(); - if (!$firstCoordinate) { - $firstCoordinate = $lastCoordinate; + if ($cell !== null) { + $lastCoordinate = $cell->getCoordinate(); + if (!$firstCoordinate) { + $firstCoordinate = $lastCoordinate; + } } } self::assertEquals($expectedResultFirst, $firstCoordinate); diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php b/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php index 919da9ef..c527f434 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php @@ -65,6 +65,22 @@ class RowIteratorTest extends TestCase } } + public function testIteratorResetStart(): void + { + $iterator = new RowIterator($this->mockWorksheet, 2, 4); + $iterator->resetStart(5); + + $key = $iterator->key(); + self::assertSame(5, $key); + + $lastRow = $iterator->key(); + while ($iterator->valid() !== false) { + $iterator->next(); + $lastRow = $iterator->key(); + } + self::assertSame(6, $lastRow); + } + public function testSeekOutOfRange(): void { $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); @@ -79,4 +95,12 @@ class RowIteratorTest extends TestCase $iterator->prev(); self::assertFalse($iterator->valid()); } + + public function testResetStartOutOfRange(): void + { + $this->expectException(\PhpOffice\PhpSpreadsheet\Exception::class); + + $iterator = new RowIterator($this->mockWorksheet, 2, 4); + $iterator->resetStart(10); + } } diff --git a/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php b/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php index 001531f8..accaf03e 100644 --- a/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php +++ b/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php @@ -15,59 +15,85 @@ $baseTestData = [ 12 => ['A' => 89], ]; +$hiddenRows = [ + 1 => false, + 2 => true, + 3 => false, + 4 => true, + 5 => false, + 6 => false, + 7 => false, + 8 => true, + 9 => false, + 10 => true, + 11 => true, + 12 => false, +]; + return [ [ 21, + $hiddenRows, 101, $baseTestData, ], [ 5, + $hiddenRows, 102, $baseTestData, ], [ 5, + $hiddenRows, 103, $baseTestData, ], [ 55, + $hiddenRows, 104, $baseTestData, ], [ 1, + $hiddenRows, 105, $baseTestData, ], [ 48620, + $hiddenRows, 106, $baseTestData, ], [ 23.1840462387393, + $hiddenRows, 107, $baseTestData, ], [ 20.7364413533277, + $hiddenRows, 108, $baseTestData, ], [ 105, + $hiddenRows, 109, $baseTestData, ], [ 537.5, + $hiddenRows, 110, $baseTestData, ], [ 430, + $hiddenRows, 111, $baseTestData, ], From 5afda811c9f742f7518e0d3938beae28d56e8238 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Thu, 18 Feb 2021 19:17:47 +0100 Subject: [PATCH 067/187] Advanced Value Binder Improvements (#1862) Advanced Value Binder - Improved format checking/setting for fractions; - Better percentage checking; - Some minor refactoring; - Improved unit testing --- .../Cell/AdvancedValueBinder.php | 102 ++++++---- .../Cell/DefaultValueBinder.php | 30 +-- .../Cell/AdvancedValueBinderTest.php | 188 ++++++++++++++++-- ...ueBinderWithOverriddenDataTypeForValue.php | 4 +- 4 files changed, 248 insertions(+), 76 deletions(-) diff --git a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php index cf638d05..69407e96 100644 --- a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php +++ b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php @@ -20,8 +20,10 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder */ public function bindValue(Cell $cell, $value = null) { - // sanitize UTF-8 strings - if (is_string($value)) { + if ($value === null) { + return parent::bindValue($cell, $value); + } elseif (is_string($value)) { + // sanitize UTF-8 strings $value = StringHelper::sanitizeUTF8($value); } @@ -41,50 +43,16 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder return true; } - // Check for number in scientific format - if (preg_match('/^' . Calculation::CALCULATION_REGEXP_NUMBER . '$/', $value)) { - $cell->setValueExplicit((float) $value, DataType::TYPE_NUMERIC); - - return true; - } - - // Check for fraction + // Check for fractions if (preg_match('/^([+-]?)\s*(\d+)\s?\/\s*(\d+)$/', $value, $matches)) { - // Convert value to number - $value = $matches[2] / $matches[3]; - if ($matches[1] == '-') { - $value = 0 - $value; - } - $cell->setValueExplicit((float) $value, DataType::TYPE_NUMERIC); - // Set style - $cell->getWorksheet()->getStyle($cell->getCoordinate()) - ->getNumberFormat()->setFormatCode('??/??'); - - return true; + return $this->setProperFraction($matches, $cell); } elseif (preg_match('/^([+-]?)(\d*) +(\d*)\s?\/\s*(\d*)$/', $value, $matches)) { - // Convert value to number - $value = $matches[2] + ($matches[3] / $matches[4]); - if ($matches[1] == '-') { - $value = 0 - $value; - } - $cell->setValueExplicit((float) $value, DataType::TYPE_NUMERIC); - // Set style - $cell->getWorksheet()->getStyle($cell->getCoordinate()) - ->getNumberFormat()->setFormatCode('# ??/??'); - - return true; + return $this->setImproperFraction($matches, $cell); } // Check for percentage if (preg_match('/^\-?\d*\.?\d*\s?\%$/', $value)) { - // Convert value to number - $value = (float) str_replace('%', '', $value) / 100; - $cell->setValueExplicit($value, DataType::TYPE_NUMERIC); - // Set style - $cell->getWorksheet()->getStyle($cell->getCoordinate()) - ->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_PERCENTAGE_00); - - return true; + return $this->setPercentage($value, $cell); } // Check for currency @@ -158,7 +126,6 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder // Check for newline character "\n" if (strpos($value, "\n") !== false) { - $value = StringHelper::sanitizeUTF8($value); $cell->setValueExplicit($value, DataType::TYPE_STRING); // Set style $cell->getWorksheet()->getStyle($cell->getCoordinate()) @@ -171,4 +138,57 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder // Not bound yet? Use parent... return parent::bindValue($cell, $value); } + + protected function setImproperFraction(array $matches, Cell $cell): bool + { + // Convert value to number + $value = $matches[2] + ($matches[3] / $matches[4]); + if ($matches[1] === '-') { + $value = 0 - $value; + } + $cell->setValueExplicit((float) $value, DataType::TYPE_NUMERIC); + + // Build the number format mask based on the size of the matched values + $dividend = str_repeat('?', strlen($matches[3])); + $divisor = str_repeat('?', strlen($matches[4])); + $fractionMask = "# {$dividend}/{$divisor}"; + // Set style + $cell->getWorksheet()->getStyle($cell->getCoordinate()) + ->getNumberFormat()->setFormatCode($fractionMask); + + return true; + } + + protected function setProperFraction(array $matches, Cell $cell): bool + { + // Convert value to number + $value = $matches[2] / $matches[3]; + if ($matches[1] === '-') { + $value = 0 - $value; + } + $cell->setValueExplicit((float) $value, DataType::TYPE_NUMERIC); + + // Build the number format mask based on the size of the matched values + $dividend = str_repeat('?', strlen($matches[2])); + $divisor = str_repeat('?', strlen($matches[3])); + $fractionMask = "{$dividend}/{$divisor}"; + // Set style + $cell->getWorksheet()->getStyle($cell->getCoordinate()) + ->getNumberFormat()->setFormatCode($fractionMask); + + return true; + } + + protected function setPercentage(string $value, Cell $cell): bool + { + // Convert value to number + $value = ((float) str_replace('%', '', $value)) / 100; + $cell->setValueExplicit($value, DataType::TYPE_NUMERIC); + + // Set style + $cell->getWorksheet()->getStyle($cell->getCoordinate()) + ->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_PERCENTAGE_00); + + return true; + } } diff --git a/src/PhpSpreadsheet/Cell/DefaultValueBinder.php b/src/PhpSpreadsheet/Cell/DefaultValueBinder.php index 693446e6..6fae5e76 100644 --- a/src/PhpSpreadsheet/Cell/DefaultValueBinder.php +++ b/src/PhpSpreadsheet/Cell/DefaultValueBinder.php @@ -40,39 +40,39 @@ class DefaultValueBinder implements IValueBinder /** * DataType for value. * - * @param mixed $pValue + * @param mixed $value * * @return string */ - public static function dataTypeForValue($pValue) + public static function dataTypeForValue($value) { // Match the value against a few data types - if ($pValue === null) { + if ($value === null) { return DataType::TYPE_NULL; - } elseif (is_float($pValue) || is_int($pValue)) { + } elseif (is_float($value) || is_int($value)) { return DataType::TYPE_NUMERIC; - } elseif (is_bool($pValue)) { + } elseif (is_bool($value)) { return DataType::TYPE_BOOL; - } elseif ($pValue === '') { + } elseif ($value === '') { return DataType::TYPE_STRING; - } elseif ($pValue instanceof RichText) { + } elseif ($value instanceof RichText) { return DataType::TYPE_INLINE; - } elseif (is_string($pValue) && $pValue[0] === '=' && strlen($pValue) > 1) { + } elseif (is_string($value) && $value[0] === '=' && strlen($value) > 1) { return DataType::TYPE_FORMULA; - } elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $pValue)) { - $tValue = ltrim($pValue, '+-'); - if (is_string($pValue) && $tValue[0] === '0' && strlen($tValue) > 1 && $tValue[1] !== '.') { + } elseif (preg_match('/^[\+\-]?(\d+\\.?\d*|\d*\\.?\d+)([Ee][\-\+]?[0-2]?\d{1,3})?$/', $value)) { + $tValue = ltrim($value, '+-'); + if (is_string($value) && $tValue[0] === '0' && strlen($tValue) > 1 && $tValue[1] !== '.') { return DataType::TYPE_STRING; - } elseif ((strpos($pValue, '.') === false) && ($pValue > PHP_INT_MAX)) { + } elseif ((strpos($value, '.') === false) && ($value > PHP_INT_MAX)) { return DataType::TYPE_STRING; - } elseif (!is_numeric($pValue)) { + } elseif (!is_numeric($value)) { return DataType::TYPE_STRING; } return DataType::TYPE_NUMERIC; - } elseif (is_string($pValue)) { + } elseif (is_string($value)) { $errorCodes = DataType::getErrorCodes(); - if (isset($errorCodes[$pValue])) { + if (isset($errorCodes[$value])) { return DataType::TYPE_ERROR; } } diff --git a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php index 630a2944..8950dfd6 100644 --- a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php @@ -33,25 +33,8 @@ class AdvancedValueBinderTest extends TestCase StringHelper::setThousandsSeparator($this->thousandsSeparator); } - public function provider() - { - $currencyUSD = NumberFormat::FORMAT_CURRENCY_USD_SIMPLE; - $currencyEURO = str_replace('$', '€', NumberFormat::FORMAT_CURRENCY_USD_SIMPLE); - - return [ - ['10%', 0.1, NumberFormat::FORMAT_PERCENTAGE_00, ',', '.', '$'], - ['$10.11', 10.11, $currencyUSD, ',', '.', '$'], - ['$1,010.12', 1010.12, $currencyUSD, ',', '.', '$'], - ['$20,20', 20.2, $currencyUSD, '.', ',', '$'], - ['$2.020,20', 2020.2, $currencyUSD, '.', ',', '$'], - ['€2.020,20', 2020.2, $currencyEURO, '.', ',', '€'], - ['€ 2.020,20', 2020.2, $currencyEURO, '.', ',', '€'], - ['€2,020.22', 2020.22, $currencyEURO, ',', '.', '€'], - ]; - } - /** - * @dataProvider provider + * @dataProvider currencyProvider * * @param mixed $value * @param mixed $valueBinded @@ -96,4 +79,173 @@ class AdvancedValueBinderTest extends TestCase $binder->bindValue($cell, $value); self::assertEquals($valueBinded, $cell->getValue()); } + + public function currencyProvider() + { + $currencyUSD = NumberFormat::FORMAT_CURRENCY_USD_SIMPLE; + $currencyEURO = str_replace('$', '€', NumberFormat::FORMAT_CURRENCY_USD_SIMPLE); + + return [ + ['$10.11', 10.11, $currencyUSD, ',', '.', '$'], + ['$1,010.12', 1010.12, $currencyUSD, ',', '.', '$'], + ['$20,20', 20.2, $currencyUSD, '.', ',', '$'], + ['$2.020,20', 2020.2, $currencyUSD, '.', ',', '$'], + ['€2.020,20', 2020.2, $currencyEURO, '.', ',', '€'], + ['€ 2.020,20', 2020.2, $currencyEURO, '.', ',', '€'], + ['€2,020.22', 2020.22, $currencyEURO, ',', '.', '€'], + ]; + } + + /** + * @dataProvider fractionProvider + * + * @param mixed $value + * @param mixed $valueBinded + * @param mixed $format + */ + public function testFractions($value, $valueBinded, $format): void + { + $sheet = $this->getMockBuilder(Worksheet::class) + ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->getMock(); + + $cellCollection = $this->getMockBuilder(Cells::class) + ->disableOriginalConstructor() + ->getMock(); + $cellCollection->expects(self::any()) + ->method('getParent') + ->willReturn($sheet); + + $sheet->expects(self::once()) + ->method('getStyle') + ->willReturnSelf(); + $sheet->expects(self::once()) + ->method('getNumberFormat') + ->willReturnSelf(); + $sheet->expects(self::once()) + ->method('setFormatCode') + ->with($format) + ->willReturnSelf(); + $sheet->expects(self::any()) + ->method('getCellCollection') + ->willReturn($cellCollection); + + $cell = new Cell(null, DataType::TYPE_STRING, $sheet); + + $binder = new AdvancedValueBinder(); + $binder->bindValue($cell, $value); + self::assertEquals($valueBinded, $cell->getValue()); + } + + public function fractionProvider() + { + return [ + ['1/5', 0.2, '?/?'], + ['-1/5', -0.2, '?/?'], + ['12/5', 2.4, '??/?'], + ['2/100', 0.02, '?/???'], + ['15/12', 1.25, '??/??'], + ['20/100', 0.2, '??/???'], + ['1 3/5', 1.6, '# ?/?'], + ['-1 3/5', -1.6, '# ?/?'], + ['1 4/20', 1.2, '# ?/??'], + ['1 16/20', 1.8, '# ??/??'], + ['12 20/100', 12.2, '# ??/???'], + ]; + } + + /** + * @dataProvider percentageProvider + * + * @param mixed $value + * @param mixed $valueBinded + * @param mixed $format + */ + public function testPercentages($value, $valueBinded, $format): void + { + $sheet = $this->getMockBuilder(Worksheet::class) + ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->getMock(); + $cellCollection = $this->getMockBuilder(Cells::class) + ->disableOriginalConstructor() + ->getMock(); + $cellCollection->expects(self::any()) + ->method('getParent') + ->willReturn($sheet); + + $sheet->expects(self::once()) + ->method('getStyle') + ->willReturnSelf(); + $sheet->expects(self::once()) + ->method('getNumberFormat') + ->willReturnSelf(); + $sheet->expects(self::once()) + ->method('setFormatCode') + ->with($format) + ->willReturnSelf(); + $sheet->expects(self::any()) + ->method('getCellCollection') + ->willReturn($cellCollection); + + $cell = new Cell(null, DataType::TYPE_STRING, $sheet); + + $binder = new AdvancedValueBinder(); + $binder->bindValue($cell, $value); + self::assertEquals($valueBinded, $cell->getValue()); + } + + public function percentageProvider() + { + return [ + ['10%', 0.1, NumberFormat::FORMAT_PERCENTAGE_00], + ['-12%', -0.12, NumberFormat::FORMAT_PERCENTAGE_00], + ['120%', 1.2, NumberFormat::FORMAT_PERCENTAGE_00], + ]; + } + + /** + * @dataProvider stringProvider + * + * @param mixed $value + * @param mixed $wrapped + */ + public function testStringWrapping(string $value, bool $wrapped): void + { + $sheet = $this->getMockBuilder(Worksheet::class) + ->setMethods(['getStyle', 'getAlignment', 'setWrapText', 'getCellCollection']) + ->getMock(); + $cellCollection = $this->getMockBuilder(Cells::class) + ->disableOriginalConstructor() + ->getMock(); + $cellCollection->expects(self::any()) + ->method('getParent') + ->willReturn($sheet); + + $sheet->expects($wrapped ? self::once() : self::never()) + ->method('getStyle') + ->willReturnSelf(); + $sheet->expects($wrapped ? self::once() : self::never()) + ->method('getAlignment') + ->willReturnSelf(); + $sheet->expects($wrapped ? self::once() : self::never()) + ->method('setWrapText') + ->with($wrapped) + ->willReturnSelf(); + $sheet->expects(self::any()) + ->method('getCellCollection') + ->willReturn($cellCollection); + + $cell = new Cell(null, DataType::TYPE_STRING, $sheet); + + $binder = new AdvancedValueBinder(); + $binder->bindValue($cell, $value); + } + + public function stringProvider() + { + return [ + ['Hello World', false], + ["Hello\nWorld", true], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php b/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php index d1b025a9..830e712a 100644 --- a/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php +++ b/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php @@ -8,10 +8,10 @@ class ValueBinderWithOverriddenDataTypeForValue extends DefaultValueBinder { public static $called = false; - public static function dataTypeForValue($pValue) + public static function dataTypeForValue($value) { self::$called = true; - return parent::dataTypeForValue($pValue); + return parent::dataTypeForValue($value); } } From b269c26f6eebfaf6d2fe734be2adc4eead48f236 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Thu, 18 Feb 2021 23:14:14 +0100 Subject: [PATCH 068/187] Advanced Value Binder improvements (#1863) * Refactor times, and add unit tests --- .../Cell/AdvancedValueBinder.php | 49 ++++++++++------- .../Cell/AdvancedValueBinderTest.php | 53 +++++++++++++++++++ 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php index 69407e96..025a687b 100644 --- a/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php +++ b/src/PhpSpreadsheet/Cell/AdvancedValueBinder.php @@ -83,29 +83,12 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder // Check for time without seconds e.g. '9:45', '09:45' if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d$/', $value)) { - // Convert value to number - [$h, $m] = explode(':', $value); - $days = $h / 24 + $m / 1440; - $cell->setValueExplicit($days, DataType::TYPE_NUMERIC); - // Set style - $cell->getWorksheet()->getStyle($cell->getCoordinate()) - ->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_TIME3); - - return true; + return $this->setTimeHoursMinutes($value, $cell); } // Check for time with seconds '9:45:59', '09:45:59' if (preg_match('/^(\d|[0-1]\d|2[0-3]):[0-5]\d:[0-5]\d$/', $value)) { - // Convert value to number - [$h, $m, $s] = explode(':', $value); - $days = $h / 24 + $m / 1440 + $s / 86400; - // Convert value to number - $cell->setValueExplicit($days, DataType::TYPE_NUMERIC); - // Set style - $cell->getWorksheet()->getStyle($cell->getCoordinate()) - ->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_TIME4); - - return true; + return $this->setTimeHoursMinutesSeconds($value, $cell); } // Check for datetime, e.g. '2008-12-31', '2008-12-31 15:59', '2008-12-31 15:59:10' @@ -191,4 +174,32 @@ class AdvancedValueBinder extends DefaultValueBinder implements IValueBinder return true; } + + protected function setTimeHoursMinutes(string $value, Cell $cell): bool + { + // Convert value to number + [$hours, $minutes] = explode(':', $value); + $days = ($hours / 24) + ($minutes / 1440); + $cell->setValueExplicit($days, DataType::TYPE_NUMERIC); + + // Set style + $cell->getWorksheet()->getStyle($cell->getCoordinate()) + ->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_TIME3); + + return true; + } + + protected function setTimeHoursMinutesSeconds(string $value, Cell $cell): bool + { + // Convert value to number + [$hours, $minutes, $seconds] = explode(':', $value); + $days = ($hours / 24) + ($minutes / 1440) + ($seconds / 86400); + $cell->setValueExplicit($days, DataType::TYPE_NUMERIC); + + // Set style + $cell->getWorksheet()->getStyle($cell->getCoordinate()) + ->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_TIME4); + + return true; + } } diff --git a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php index 8950dfd6..eefa7b83 100644 --- a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php @@ -200,6 +200,59 @@ class AdvancedValueBinderTest extends TestCase ['10%', 0.1, NumberFormat::FORMAT_PERCENTAGE_00], ['-12%', -0.12, NumberFormat::FORMAT_PERCENTAGE_00], ['120%', 1.2, NumberFormat::FORMAT_PERCENTAGE_00], + ['12.5%', 0.125, NumberFormat::FORMAT_PERCENTAGE_00], + ]; + } + + /** + * @dataProvider timeProvider + * + * @param mixed $value + * @param mixed $valueBinded + * @param mixed $format + */ + public function testTimes($value, $valueBinded, $format): void + { + $sheet = $this->getMockBuilder(Worksheet::class) + ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->getMock(); + + $cellCollection = $this->getMockBuilder(Cells::class) + ->disableOriginalConstructor() + ->getMock(); + $cellCollection->expects(self::any()) + ->method('getParent') + ->willReturn($sheet); + + $sheet->expects(self::once()) + ->method('getStyle') + ->willReturnSelf(); + $sheet->expects(self::once()) + ->method('getNumberFormat') + ->willReturnSelf(); + $sheet->expects(self::once()) + ->method('setFormatCode') + ->with($format) + ->willReturnSelf(); + $sheet->expects(self::any()) + ->method('getCellCollection') + ->willReturn($cellCollection); + + $cell = new Cell(null, DataType::TYPE_STRING, $sheet); + + $binder = new AdvancedValueBinder(); + $binder->bindValue($cell, $value); + self::assertEquals($valueBinded, $cell->getValue()); + } + + public function timeProvider() + { + return [ + ['1:20', 0.05555555556, NumberFormat::FORMAT_DATE_TIME3], + ['09:17', 0.386805555556, NumberFormat::FORMAT_DATE_TIME3], + ['15:00', 0.625, NumberFormat::FORMAT_DATE_TIME3], + ['17:12:35', 0.71707175926, NumberFormat::FORMAT_DATE_TIME4], + ['23:58:20', 0.99884259259, NumberFormat::FORMAT_DATE_TIME4], ]; } From 409c05b5423404fa70826ad64c9c0da6ebadfbb8 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 19 Feb 2021 08:41:26 +0100 Subject: [PATCH 069/187] Additional Unit Test Cases for Convert UoM (#1864) * Additional Unit Test Cases --- .../Functions/Engineering/ConvertUoMTest.php | 6 +++ .../Calculation/Engineering/CONVERTUOM.php | 48 +++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php index 7a18067f..cf43c759 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php @@ -37,6 +37,12 @@ class ConvertUoMTest extends TestCase self::assertIsArray($result); } + public function testGetBinaryConversionMultipliers(): void + { + $result = Engineering::getBinaryConversionMultipliers(); + self::assertIsArray($result); + } + /** * @dataProvider providerCONVERTUOM * diff --git a/tests/data/Calculation/Engineering/CONVERTUOM.php b/tests/data/Calculation/Engineering/CONVERTUOM.php index 64aaef62..420fa2d0 100644 --- a/tests/data/Calculation/Engineering/CONVERTUOM.php +++ b/tests/data/Calculation/Engineering/CONVERTUOM.php @@ -139,6 +139,18 @@ return [ 'K', 'Reau', ], + 'Melting Point of Titanium (Rankine to K)' => [ + 1941, + 3493.8, + 'Rank', + 'K', + ], + 'Melting Point of Titanium (Réaumur to K)' => [ + 1941, + 1334.28, + 'Reau', + 'K', + ], 'Temperature synonyms (K)' => [ 123.45, 123.45, @@ -157,12 +169,18 @@ return [ 'F', 'fah', ], - 'Invalid value to conver' => [ + 'Invalid value to convert' => [ '#VALUE!', 'three', 'ft', 'yds', ], + 'Imperial to 2-character prefixed imperial, same unit' => [ + '#N/A', + 100.0, + 'pt', + 'dapt', + ], 'Prefixed metric to binary prefixed metric' => [ '#N/A', 12.345, @@ -175,18 +193,42 @@ return [ 'ft', 'day', ], - 'From Prefixed imperial (Invalid)' => [ + 'From prefixed Imperial (Invalid)' => [ '#N/A', 234.56, 'kpt', 'lt', ], - 'To prefixed imperial (Invalid)' => [ + 'To prefixed Imperial (Invalid)' => [ '#N/A', 234.56, 'lt', 'kpt', ], + 'From binary prefixed Imperial (Invalid)' => [ + '#N/A', + 234.56, + 'kiqt', + 'pt', + ], + 'To binary prefixed Imperial (Invalid)' => [ + '#N/A', + 234.56, + 'pt', + 'kiqt', + ], + 'From prefixed Imperial 2 (Invalid)' => [ + '#N/A', + 12345.6, + 'baton', + 'cwt', + ], + 'To prefixed Imperial 2 (Invalid)' => [ + '#N/A', + 12345.6, + 'cwt', + 'baton', + ], 'Invalid from unit' => [ '#N/A', 234.56, From b0eb272ce1d98a454dbbfb665a131a12b7ffefb7 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 19 Feb 2021 12:28:07 +0100 Subject: [PATCH 070/187] Bugfix #1858; `getCell()` method should support named cells correctly (#1865) Resolution for Issue [#1858](https://github.com/PHPOffice/PhpSpreadsheet/issues/1858) --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Worksheet/Worksheet.php | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddfd2fc3..bdeaaa8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Nothing. ### Fixed +- Fixed issue with Worksheet's `getCell()` method when trying to get a cell by defined name. [#1858](https://github.com/PHPOffice/PhpSpreadsheet/issues/1858) - Fix possible endless loop in NumberFormat Masks [#1792](https://github.com/PHPOffice/PhpSpreadsheet/issues/1792) - Fix problem resulting from literal dot inside quotes in number format masks. [PR #1830](https://github.com/PHPOffice/PhpSpreadsheet/pull/1830) - Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. [PR #1761](https://github.com/PHPOffice/PhpSpreadsheet/pull/1761) diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 19833b71..c6f655c3 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -1186,7 +1186,8 @@ class Worksheet implements IComparable if (strpos($pCoordinate, '!') !== false) { $worksheetReference = self::extractSheetTitle($pCoordinate, true); - return $this->parent->getSheetByName($worksheetReference[0])->getCell(strtoupper($worksheetReference[1]), $createIfNotExists); + return $this->parent->getSheetByName($worksheetReference[0]) + ->getCell(strtoupper($worksheetReference[1]), $createIfNotExists); } // Named range? @@ -1196,7 +1197,7 @@ class Worksheet implements IComparable ) { $namedRange = DefinedName::resolveName($pCoordinate, $this); if ($namedRange !== null) { - $pCoordinate = $namedRange->getValue(); + $pCoordinate = str_replace('$', '', $namedRange->getValue()); return $namedRange->getWorksheet()->getCell($pCoordinate, $createIfNotExists); } @@ -1296,7 +1297,7 @@ class Worksheet implements IComparable ) { $namedRange = DefinedName::resolveName($pCoordinate, $this); if ($namedRange !== null) { - $pCoordinate = $namedRange->getValue(); + $pCoordinate = str_replace('$', '', $namedRange->getValue()); if ($this->getHashCode() != $namedRange->getWorksheet()->getHashCode()) { if (!$namedRange->getLocalOnly()) { return $namedRange->getWorksheet()->cellExists($pCoordinate); @@ -2567,7 +2568,7 @@ class Worksheet implements IComparable $namedRange = DefinedName::resolveName($pNamedRange, $this); if ($namedRange !== null) { $pWorkSheet = $namedRange->getWorksheet(); - $pCellRange = $namedRange->getValue(); + $pCellRange = str_replace('$', '', $namedRange->getValue()); return $pWorkSheet->rangeToArray($pCellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef); } From 1318b90330773d852ee15c8b432a7e7175c4bd55 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 19 Feb 2021 22:03:50 +0100 Subject: [PATCH 071/187] Bugfix #1858; Apply stricter scoping rules to named range/cell access (#1866) * Apply stricter scoping rules to named range/cell access via Worksheet object * Additional unit tests --- src/PhpSpreadsheet/Worksheet/Worksheet.php | 70 ++++++--- .../Worksheet/WorksheetNamedRangesTest.php | 143 ++++++++++++++++++ tests/data/Worksheet/namedRangeTest.xlsx | Bin 0 -> 9812 bytes 3 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php create mode 100644 tests/data/Worksheet/namedRangeTest.xlsx diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index c6f655c3..02305b7a 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -1195,11 +1195,12 @@ class Worksheet implements IComparable (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate, $matches)) && (preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate, $matches)) ) { - $namedRange = DefinedName::resolveName($pCoordinate, $this); + $namedRange = $this->validateNamedRange($pCoordinate, true); if ($namedRange !== null) { - $pCoordinate = str_replace('$', '', $namedRange->getValue()); + $cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); + $cellCoordinate = str_replace('$', '', $cellCoordinate); - return $namedRange->getWorksheet()->getCell($pCoordinate, $createIfNotExists); + return $namedRange->getWorksheet()->getCell($cellCoordinate, $createIfNotExists); } } @@ -1295,18 +1296,12 @@ class Worksheet implements IComparable (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate, $matches)) && (preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate, $matches)) ) { - $namedRange = DefinedName::resolveName($pCoordinate, $this); + $namedRange = $this->validateNamedRange($pCoordinate, true); if ($namedRange !== null) { - $pCoordinate = str_replace('$', '', $namedRange->getValue()); - if ($this->getHashCode() != $namedRange->getWorksheet()->getHashCode()) { - if (!$namedRange->getLocalOnly()) { - return $namedRange->getWorksheet()->cellExists($pCoordinate); - } + $cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); + $cellCoordinate = str_replace('$', '', $cellCoordinate); - throw new Exception('Named range ' . $namedRange->getName() . ' is not accessible from within sheet ' . $this->getTitle()); - } - } else { - return false; + return $namedRange->getWorksheet()->cellExists($cellCoordinate); } } @@ -2551,10 +2546,42 @@ class Worksheet implements IComparable return $returnValue; } + private function validateNamedRange(string $definedName, bool $returnNullIfInvalid = false): ?DefinedName + { + $namedRange = DefinedName::resolveName($definedName, $this); + if ($namedRange === null) { + if ($returnNullIfInvalid) { + return null; + } + + throw new Exception('Named Range ' . $definedName . ' does not exist.'); + } + + if ($namedRange->isFormula()) { + if ($returnNullIfInvalid) { + return null; + } + + 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; + } + + throw new Exception( + 'Named range ' . $definedName . ' is not accessible from within sheet ' . $this->getTitle() + ); + } + + return $namedRange; + } + /** * Create array from a range of cells. * - * @param string $pNamedRange Name of the Named Range + * @param string $definedName The Named Range that should be returned * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist * @param bool $calculateFormulas Should formulas be calculated? * @param bool $formatData Should formatting be applied to cell values? @@ -2563,17 +2590,14 @@ class Worksheet implements IComparable * * @return array */ - public function namedRangeToArray($pNamedRange, $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) + public function namedRangeToArray(string $definedName, $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false) { - $namedRange = DefinedName::resolveName($pNamedRange, $this); - if ($namedRange !== null) { - $pWorkSheet = $namedRange->getWorksheet(); - $pCellRange = str_replace('$', '', $namedRange->getValue()); + $namedRange = $this->validateNamedRange($definedName); + $workSheet = $namedRange->getWorksheet(); + $cellRange = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); + $cellRange = str_replace('$', '', $cellRange); - return $pWorkSheet->rangeToArray($pCellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef); - } - - throw new Exception('Named Range ' . $pNamedRange . ' does not exist.'); + return $workSheet->rangeToArray($cellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef); } /** diff --git a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php new file mode 100644 index 00000000..62238b68 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php @@ -0,0 +1,143 @@ +spreadsheet = $reader->load('tests/data/Worksheet/namedRangeTest.xlsx'); + } + + public function testCellExists(): void + { + $namedCell = 'GREETING'; + + $worksheet = $this->spreadsheet->getActiveSheet(); + $cellExists = $worksheet->cellExists($namedCell); + self::assertTrue($cellExists); + } + + public function testCellNotExists(): void + { + $namedCell = 'GOODBYE'; + + $worksheet = $this->spreadsheet->getActiveSheet(); + $cellExists = $worksheet->cellExists($namedCell); + self::assertFalse($cellExists); + } + + public function testCellExistsInvalidScope(): void + { + $namedCell = 'Result'; + + $worksheet = $this->spreadsheet->getActiveSheet(); + $cellExists = $worksheet->cellExists($namedCell); + self::assertFalse($cellExists); + } + + public function testCellExistsRange(): void + { + $namedRange = 'Range1'; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Cell coordinate can not be a range of cells'); + + $worksheet = $this->spreadsheet->getActiveSheet(); + $worksheet->cellExists($namedRange); + } + + public function testGetCell(): void + { + $namedCell = 'GREETING'; + + $worksheet = $this->spreadsheet->getActiveSheet(); + $cell = $worksheet->getCell($namedCell); + self::assertSame('Hello', $cell->getValue()); + } + + public function testGetCellNotExists(): void + { + $namedCell = 'GOODBYE'; + + $this->expectException(Exception::class); + $this->expectExceptionMessage("Invalid cell coordinate {$namedCell}"); + + $worksheet = $this->spreadsheet->getActiveSheet(); + $worksheet->getCell($namedCell); + } + + public function testGetCellInvalidScope(): void + { + $namedCell = 'Result'; + $ucNamedCell = strtoupper($namedCell); + + $this->expectException(Exception::class); + $this->expectExceptionMessage("Invalid cell coordinate {$ucNamedCell}"); + + $worksheet = $this->spreadsheet->getActiveSheet(); + $worksheet->getCell($namedCell); + } + + public function testGetCellLocalScoped(): void + { + $namedCell = 'Result'; + + $this->spreadsheet->setActiveSheetIndexByName('Sheet2'); + $worksheet = $this->spreadsheet->getActiveSheet(); + $cell = $worksheet->getCell($namedCell); + self::assertSame(8, $cell->getCalculatedValue()); + } + + public function testGetCellNamedFormula(): void + { + $namedCell = 'Result'; + + $this->spreadsheet->setActiveSheetIndexByName('Sheet2'); + $worksheet = $this->spreadsheet->getActiveSheet(); + $cell = $worksheet->getCell($namedCell); + self::assertSame(8, $cell->getCalculatedValue()); + } + + public function testGetCellWithNamedRange(): void + { + $namedCell = 'Range1'; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Cell coordinate can not be a range of cells'); + + $worksheet = $this->spreadsheet->getActiveSheet(); + $worksheet->getCell($namedCell); + } + + public function testNamedRangeToArray(): void + { + $namedRange = 'Range1'; + + $worksheet = $this->spreadsheet->getActiveSheet(); + $rangeData = $worksheet->namedRangeToArray($namedRange); + self::assertSame([[1, 2, 3]], $rangeData); + } + + public function testInvalidNamedRangeToArray(): void + { + $namedRange = 'Range2'; + + $this->expectException(Exception::class); + $this->expectExceptionMessage("Named Range {$namedRange} does not exist"); + + $worksheet = $this->spreadsheet->getActiveSheet(); + $rangeData = $worksheet->namedRangeToArray($namedRange); + self::assertSame([[1, 2, 3]], $rangeData); + } +} diff --git a/tests/data/Worksheet/namedRangeTest.xlsx b/tests/data/Worksheet/namedRangeTest.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a4383bb0b1b6839889a3f7725ade8214db118e8c GIT binary patch literal 9812 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 PRLBn&B2q!>-_HIYb%x#_ literal 0 HcmV?d00001 From 0bb625bc6869829affa8c07d37493124e963b930 Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Sun, 21 Feb 2021 11:36:37 +0900 Subject: [PATCH 072/187] Update Csv.php Add "outputEncoding" property. "outputEncoding" property is used by mb_convert_encoding function. --- src/PhpSpreadsheet/Writer/Csv.php | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/PhpSpreadsheet/Writer/Csv.php b/src/PhpSpreadsheet/Writer/Csv.php index 74f28636..188a83a8 100644 --- a/src/PhpSpreadsheet/Writer/Csv.php +++ b/src/PhpSpreadsheet/Writer/Csv.php @@ -64,6 +64,13 @@ class Csv extends BaseWriter */ private $excelCompatibility = false; + /** + * Output encoding. + * + * @var string + */ + private $outputEncoding = ''; + /** * Create a new CSV. * @@ -296,6 +303,30 @@ class Csv extends BaseWriter return $this; } + /** + * Get output encoding. + * + * @return string + */ + public function getOutputEncoding() + { + return $this->outputEncoding; + } + + /** + * Set output encoding. + * + * @param string $pValue Output encoding + * + * @return $this + */ + public function setOutputEncoding($pValue) + { + $this->outputEncoding = $pValue; + + return $this; + } + private $enclosureRequired = true; public function setEnclosureRequired(bool $value): self @@ -347,6 +378,9 @@ class Csv extends BaseWriter $line .= $this->lineEnding; // Write to file + if ($this->outputEncoding != '') { + $line = mb_convert_encoding($line, $this->outputEncoding); + } fwrite($pFileHandle, $line); } } From 3764f303547eb5e941738dbe362b7a6f615835c7 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 22 Feb 2021 12:46:57 +0100 Subject: [PATCH 073/187] Refactor the Excel Database functions; and rewrite the query building (#1871) * Refactor the Excel Database functions; and rewrite the query building to fix a bug with complex multi-criteria queries that involve both AND and OR conditions * Fix handling for empty cells and NULL values in searches * Expand unit tests; and add TODOs for dates, percentages, and wildcard text comparisons --- .../Calculation/Calculation.php | 25 +- src/PhpSpreadsheet/Calculation/Database.php | 308 ++++-------------- .../Calculation/Database/DAverage.php | 45 +++ .../Calculation/Database/DCount.php | 43 +++ .../Calculation/Database/DCountA.php | 42 +++ .../Calculation/Database/DGet.php | 49 +++ .../Calculation/Database/DMax.php | 46 +++ .../Calculation/Database/DMin.php | 46 +++ .../Calculation/Database/DProduct.php | 45 +++ .../Calculation/Database/DStDev.php | 46 +++ .../Calculation/Database/DStDevP.php | 46 +++ .../Calculation/Database/DSum.php | 45 +++ .../Calculation/Database/DVar.php | 46 +++ .../Calculation/Database/DVarP.php | 46 +++ .../Calculation/Database/DatabaseAbstract.php | 144 ++++++++ .../Functions/Database/DAverageTest.php | 110 +++++++ .../Functions/Database/DCountATest.php | 108 ++++++ .../Functions/Database/DCountTest.php | 103 ++++++ .../Functions/Database/DGetTest.php | 115 +++++++ .../Functions/Database/DMaxTest.php | 105 ++++++ .../Functions/Database/DMinTest.php | 101 ++++++ .../Functions/Database/DProductTest.php | 105 ++++++ .../Functions/Database/DStDevPTest.php | 101 ++++++ .../Functions/Database/DStDevTest.php | 101 ++++++ .../Functions/Database/DSumTest.php | 117 +++++++ .../Functions/Database/DVarPTest.php | 101 ++++++ .../Functions/Database/DVarTest.php | 101 ++++++ 27 files changed, 2034 insertions(+), 256 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Database/DAverage.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DCount.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DCountA.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DGet.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DMax.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DMin.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DProduct.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DStDev.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DStDevP.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DSum.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DVar.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DVarP.php create mode 100644 src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 7868ec5e..87bf44a5 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -769,7 +769,7 @@ class Calculation ], 'DAVERAGE' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DAVERAGE'], + 'functionCall' => [Database\DAverage::class, 'evaluate'], 'argumentCount' => '3', ], 'DAY' => [ @@ -799,12 +799,12 @@ class Calculation ], 'DCOUNT' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DCOUNT'], + 'functionCall' => [Database\DCount::class, 'evaluate'], 'argumentCount' => '3', ], 'DCOUNTA' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DCOUNTA'], + 'functionCall' => [Database\DCountA::class, 'evaluate'], 'argumentCount' => '3', ], 'DDB' => [ @@ -849,7 +849,7 @@ class Calculation ], 'DGET' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DGET'], + 'functionCall' => [Database\DGet::class, 'evaluate'], 'argumentCount' => '3', ], 'DISC' => [ @@ -859,12 +859,12 @@ class Calculation ], 'DMAX' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DMAX'], + 'functionCall' => [Database\DMax::class, 'evaluate'], 'argumentCount' => '3', ], 'DMIN' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DMIN'], + 'functionCall' => [Database\DMin::class, 'evaluate'], 'argumentCount' => '3', ], 'DOLLAR' => [ @@ -884,22 +884,22 @@ class Calculation ], 'DPRODUCT' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DPRODUCT'], + 'functionCall' => [Database\DProduct::class, 'evaluate'], 'argumentCount' => '3', ], 'DSTDEV' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DSTDEV'], + 'functionCall' => [Database\DStDev::class, 'evaluate'], 'argumentCount' => '3', ], 'DSTDEVP' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DSTDEVP'], + 'functionCall' => [Database\DStDevP::class, 'evaluate'], 'argumentCount' => '3', ], 'DSUM' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DSUM'], + 'functionCall' => [Database\DSum::class, 'evaluate'], 'argumentCount' => '3', ], 'DURATION' => [ @@ -909,12 +909,12 @@ class Calculation ], 'DVAR' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DVAR'], + 'functionCall' => [Database\DVar::class, 'evaluate'], 'argumentCount' => '3', ], 'DVARP' => [ 'category' => Category::CATEGORY_DATABASE, - 'functionCall' => [Database::class, 'DVARP'], + 'functionCall' => [Database\DVarP::class, 'evaluate'], 'argumentCount' => '3', ], 'EDATE' => [ @@ -3437,6 +3437,7 @@ class Calculation $this->debugLog->writeDebugLog('Formula for cell ', $wsCellReference, ' is ', $formula); // Parse the formula onto the token stack and calculate the value $this->cyclicReferenceStack->push($wsCellReference); + $cellValue = $this->processTokenStack($this->internalParseFormula($formula, $pCell), $cellID, $pCell); $this->cyclicReferenceStack->pop(); diff --git a/src/PhpSpreadsheet/Calculation/Database.php b/src/PhpSpreadsheet/Calculation/Database.php index 5250e306..db16e2df 100644 --- a/src/PhpSpreadsheet/Calculation/Database.php +++ b/src/PhpSpreadsheet/Calculation/Database.php @@ -2,126 +2,11 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +/** + * @deprecated 1.17.0 + */ class Database { - /** - * fieldExtract. - * - * Extracts the column ID to use for the data field. - * - * @param mixed[] $database The range of cells that makes up the list or database. - * A database is a list of related data in which rows of related - * information are records, and columns of data are fields. The - * first row of the list contains labels for each column. - * @param mixed $field Indicates which column is used in the function. Enter the - * column label enclosed between double quotation marks, such as - * "Age" or "Yield," or a number (without quotation marks) that - * represents the position of the column within the list: 1 for - * the first column, 2 for the second column, and so on. - * - * @return null|string - */ - private static function fieldExtract($database, $field) - { - $field = strtoupper(Functions::flattenSingleValue($field)); - $fieldNames = array_map('strtoupper', array_shift($database)); - - if (is_numeric($field)) { - $keys = array_keys($fieldNames); - - return $keys[$field - 1]; - } - $key = array_search($field, $fieldNames); - - return $key ?: null; - } - - /** - * filter. - * - * Parses the selection criteria, extracts the database rows that match those criteria, and - * returns that subset of rows. - * - * @param mixed[] $database The range of cells that makes up the list or database. - * A database is a list of related data in which rows of related - * information are records, and columns of data are fields. The - * first row of the list contains labels for each column. - * @param mixed[] $criteria The range of cells that contains the conditions you specify. - * You can use any range for the criteria argument, as long as it - * includes at least one column label and at least one cell below - * the column label in which you specify a condition for the - * column. - * - * @return array of mixed - */ - private static function filter($database, $criteria) - { - $fieldNames = array_shift($database); - $criteriaNames = array_shift($criteria); - - // Convert the criteria into a set of AND/OR conditions with [:placeholders] - $testConditions = $testValues = []; - $testConditionsCount = 0; - foreach ($criteriaNames as $key => $criteriaName) { - $testCondition = []; - $testConditionCount = 0; - foreach ($criteria as $row => $criterion) { - if ($criterion[$key] > '') { - $testCondition[] = '[:' . $criteriaName . ']' . Functions::ifCondition($criterion[$key]); - ++$testConditionCount; - } - } - if ($testConditionCount > 1) { - $testConditions[] = 'OR(' . implode(',', $testCondition) . ')'; - ++$testConditionsCount; - } elseif ($testConditionCount == 1) { - $testConditions[] = $testCondition[0]; - ++$testConditionsCount; - } - } - - if ($testConditionsCount > 1) { - $testConditionSet = 'AND(' . implode(',', $testConditions) . ')'; - } elseif ($testConditionsCount == 1) { - $testConditionSet = $testConditions[0]; - } - - // Loop through each row of the database - foreach ($database as $dataRow => $dataValues) { - // Substitute actual values from the database row for our [:placeholders] - $testConditionList = $testConditionSet; - foreach ($criteriaNames as $key => $criteriaName) { - $k = array_search($criteriaName, $fieldNames); - if (isset($dataValues[$k])) { - $dataValue = $dataValues[$k]; - $dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; - $testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList); - } - } - // evaluate the criteria against the row data - $result = Calculation::getInstance()->_calculateFormulaValue('=' . $testConditionList); - // If the row failed to meet the criteria, remove it from the database - if (!$result) { - unset($database[$dataRow]); - } - } - - return $database; - } - - private static function getFilteredColumn($database, $field, $criteria) - { - // reduce the database to a set of rows that match all the criteria - $database = self::filter($database, $criteria); - // extract an array of values for the requested column - $colData = []; - foreach ($database as $row) { - $colData[] = $row[$field]; - } - - return $colData; - } - /** * DAVERAGE. * @@ -130,6 +15,10 @@ class Database * Excel Function: * DAVERAGE(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DAverage class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -149,15 +38,7 @@ class Database */ public static function DAVERAGE($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::AVERAGE( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DAverage::evaluate($database, $field, $criteria); } /** @@ -169,14 +50,15 @@ class Database * Excel Function: * DCOUNT(database,[field],criteria) * - * Excel Function: - * DAVERAGE(database,field,criteria) + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DCount class instead * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The * first row of the list contains labels for each column. - * @param int|string $field Indicates which column is used in the function. Enter the + * @param null|int|string $field Indicates which column is used in the function. Enter the * column label enclosed between double quotation marks, such as * "Age" or "Yield," or a number (without quotation marks) that * represents the position of the column within the list: 1 for @@ -194,15 +76,7 @@ class Database */ public static function DCOUNT($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::COUNT( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DCount::evaluate($database, $field, $criteria); } /** @@ -213,11 +87,15 @@ class Database * Excel Function: * DCOUNTA(database,[field],criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DCountA class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The * first row of the list contains labels for each column. - * @param int|string $field Indicates which column is used in the function. Enter the + * @param null|int|string $field Indicates which column is used in the function. Enter the * column label enclosed between double quotation marks, such as * "Age" or "Yield," or a number (without quotation marks) that * represents the position of the column within the list: 1 for @@ -229,29 +107,10 @@ class Database * column. * * @return int - * - * @TODO The field argument is optional. If field is omitted, DCOUNTA counts all records in the - * database that match the criteria. */ public static function DCOUNTA($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // reduce the database to a set of rows that match all the criteria - $database = self::filter($database, $criteria); - // extract an array of values for the requested column - $colData = []; - foreach ($database as $row) { - $colData[] = $row[$field]; - } - - // Return - return Statistical::COUNTA( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DCountA::evaluate($database, $field, $criteria); } /** @@ -263,6 +122,10 @@ class Database * Excel Function: * DGET(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DGet class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -282,18 +145,7 @@ class Database */ public static function DGET($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - $colData = self::getFilteredColumn($database, $field, $criteria); - if (count($colData) > 1) { - return Functions::NAN(); - } - - return $colData[0]; + return Database\DGet::evaluate($database, $field, $criteria); } /** @@ -305,6 +157,10 @@ class Database * Excel Function: * DMAX(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DMax class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -324,15 +180,7 @@ class Database */ public static function DMAX($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::MAX( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DMax::evaluate($database, $field, $criteria); } /** @@ -344,6 +192,10 @@ class Database * Excel Function: * DMIN(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DMin class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -363,15 +215,7 @@ class Database */ public static function DMIN($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::MIN( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DMin::evaluate($database, $field, $criteria); } /** @@ -382,6 +226,10 @@ class Database * Excel Function: * DPRODUCT(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DProduct class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -401,15 +249,7 @@ class Database */ public static function DPRODUCT($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return MathTrig::PRODUCT( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DProduct::evaluate($database, $field, $criteria); } /** @@ -421,6 +261,10 @@ class Database * Excel Function: * DSTDEV(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DStDev class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -440,15 +284,7 @@ class Database */ public static function DSTDEV($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::STDEV( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DStDev::evaluate($database, $field, $criteria); } /** @@ -460,6 +296,10 @@ class Database * Excel Function: * DSTDEVP(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DStDevP class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -479,15 +319,7 @@ class Database */ public static function DSTDEVP($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::STDEVP( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DStDevP::evaluate($database, $field, $criteria); } /** @@ -498,6 +330,10 @@ class Database * Excel Function: * DSUM(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DSum class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -517,15 +353,7 @@ class Database */ public static function DSUM($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return MathTrig::SUM( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DSum::evaluate($database, $field, $criteria); } /** @@ -537,6 +365,10 @@ class Database * Excel Function: * DVAR(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DVar class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -556,15 +388,7 @@ class Database */ public static function DVAR($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::VARFunc( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DVar::evaluate($database, $field, $criteria); } /** @@ -576,6 +400,10 @@ class Database * Excel Function: * DVARP(database,field,criteria) * + * @Deprecated 1.17.0 + * + * @see Use the evaluate() method in the Database\DVarP class instead + * * @param mixed[] $database The range of cells that makes up the list or database. * A database is a list of related data in which rows of related * information are records, and columns of data are fields. The @@ -595,14 +423,6 @@ class Database */ public static function DVARP($database, $field, $criteria) { - $field = self::fieldExtract($database, $field); - if ($field === null) { - return null; - } - - // Return - return Statistical::VARP( - self::getFilteredColumn($database, $field, $criteria) - ); + return Database\DVarP::evaluate($database, $field, $criteria); } } diff --git a/src/PhpSpreadsheet/Calculation/Database/DAverage.php b/src/PhpSpreadsheet/Calculation/Database/DAverage.php new file mode 100644 index 00000000..899b2426 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Database/DAverage.php @@ -0,0 +1,45 @@ + 1) { + return Functions::NAN(); + } + + return $columnData[0]; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Database/DMax.php b/src/PhpSpreadsheet/Calculation/Database/DMax.php new file mode 100644 index 00000000..8918c54d --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Database/DMax.php @@ -0,0 +1,46 @@ +, <=, etc) + * @TODO Suport for formatted numerics (e.g. '>12.5%' => '>0.125') + * @TODO Suport for wildcard ? and * in strings (includng escaping) + */ + private static function buildQuery(array $criteriaNames, array $criteria): string + { + $baseQuery = []; + foreach ($criteria as $key => $criterion) { + foreach ($criterion as $field => $value) { + $criterionName = $criteriaNames[$field]; + if ($value !== null && $value !== '') { + $condition = '[:' . $criterionName . ']' . Functions::ifCondition($value); + $baseQuery[$key][] = $condition; + } + } + } + + $rowQuery = array_map( + function ($rowValue) { + return (count($rowValue) > 1) ? 'AND(' . implode(',', $rowValue) . ')' : $rowValue[0]; + }, + $baseQuery + ); + + return (count($rowQuery) > 1) ? 'OR(' . implode(',', $rowQuery) . ')' : $rowQuery[0]; + } + + /** + * @param $criteriaNames + * @param $fieldNames + */ + private static function executeQuery(array $database, string $query, $criteriaNames, $fieldNames): array + { + foreach ($database as $dataRow => $dataValues) { + // Substitute actual values from the database row for our [:placeholders] + $testConditionList = $query; + foreach ($criteriaNames as $key => $criteriaName) { + $key = array_search($criteriaName, $fieldNames, true); + if (isset($dataValues[$key])) { + $dataValue = $dataValues[$key]; + $dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; + } else { + $dataValue = 'NULL'; + } + $testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList); + } + + // evaluate the criteria against the row data + $result = Calculation::getInstance()->_calculateFormulaValue('=' . $testConditionList); + // If the row failed to meet the criteria, remove it from the database + + if ($result !== true) { + unset($database[$dataRow]); + } + } + + return $database; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php new file mode 100644 index 00000000..91011504 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php @@ -0,0 +1,110 @@ +database1(), + 'Yield', + [ + ['Tree', 'Height'], + ['=Apple', '>10'], + ], + ], + [ + 13, + $this->database1(), + 3, + $this->database1(), + ], + [ + 268333.333333333333, + $this->database2(), + 'Sales', + [ + ['Quarter', 'Sales Rep.'], + ['>1', 'Tina'], + ], + ], + [ + 372500, + $this->database2(), + 'Sales', + [ + ['Quarter', 'Area'], + ['1', 'South'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php new file mode 100644 index 00000000..ea856c57 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php @@ -0,0 +1,108 @@ +database1(), + 'Profit', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ], + ], + [ + 2, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Science', 'Male'], + ], + ], + /* + * Null value in datacolumn behaviour for DCOUNTA... will include not include a null value in the count + * if it is an actual cell value; but it will be included if it is a literal... this test case is + * currently passing literals + [ + 1, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Math', 'Female'], + ], + ], + */ + [ + 3, + $this->database2(), + 'Score', + [ + ['Subject', 'Score'], + ['English', '>0.60'], + ], + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php new file mode 100644 index 00000000..9e12ac96 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php @@ -0,0 +1,103 @@ +database1(), + 'Age', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ], + ], + [ + 1, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Science', 'Male'], + ], + ], + [ + 1, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Math', 'Female'], + ], + ], + [ + 3, + $this->database2(), + null, + [ + ['Subject', 'Score'], + ['English', '>0.63'], + ], + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php new file mode 100644 index 00000000..3d90ff96 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php @@ -0,0 +1,115 @@ +database1(), + 'Yield', + [ + ['Tree'], + ['=Apple'], + ['=Pear'], + ], + ], + [ + 10, + $this->database1(), + 'Yield', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ['=Pear', '>12', null], + ], + ], + [ + 188000, + $this->database2(), + 'Sales', + [ + ['Sales Rep.', 'Quarter'], + ['Tina', 4], + ], + ], + [ + Functions::NAN(), + $this->database2(), + 'Sales', + [ + ['Area', 'Quarter'], + ['South', 4], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php new file mode 100644 index 00000000..b0ad59a7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php @@ -0,0 +1,105 @@ +database1(), + 'Profit', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ['=Pear', null, null], + ], + ], + [ + 340000, + $this->database2(), + 'Sales', + [ + ['Quarter', 'Area'], + [2, 'North'], + ], + ], + [ + 460000, + $this->database2(), + 'Sales', + [ + ['Sales Rep.', 'Quarter'], + ['Carol', '>1'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php new file mode 100644 index 00000000..bfd2af4c --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php @@ -0,0 +1,101 @@ +database1(), + 'Profit', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ['=Pear', '>12', null], + ], + ], + [ + 0.48, + $this->database2(), + 'Score', + [ + ['Subject', 'Age'], + ['Science', '>8'], + ], + ], + [ + 0.55, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Math', 'Male'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php new file mode 100644 index 00000000..9b2f92b3 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php @@ -0,0 +1,105 @@ +database1(), + 'Yield', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ['=Pear', null, null], + ], + ], + /* + * We don't yet support date handling in the search query + [ + 36, + $this->database2(), + 'Score', + [ + ['Name', 'Date'], + ['Gary', '05-Jan-2017'], + ], + ], + [ + 8, + $this->database2(), + 'Score', + [ + ['Test', 'Date'], + ['Test1', '<05-Jan-2017'], + ], + ], + */ + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php new file mode 100644 index 00000000..210325d5 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php @@ -0,0 +1,101 @@ +database1(), + 'Yield', + [ + ['Tree'], + ['=Apple'], + ['=Pear'], + ], + ], + [ + 0.085244745684, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['English', 'Male'], + ], + ], + [ + 0.160623784042, + $this->database2(), + 'Score', + [ + ['Subject', 'Age'], + ['Math', '>8'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php new file mode 100644 index 00000000..71bbcd2a --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php @@ -0,0 +1,101 @@ +database1(), + 'Yield', + [ + ['Tree'], + ['=Apple'], + ['=Pear'], + ], + ], + [ + 0.104403065089, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['English', 'Male'], + ], + ], + [ + 0.196723155729, + $this->database2(), + 'Score', + [ + ['Subject', 'Age'], + ['Math', '>8'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php new file mode 100644 index 00000000..fbb86bb9 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php @@ -0,0 +1,117 @@ +database1(), + 'Profit', + [ + ['Tree'], + ['=Apple'], + ], + ], + [ + 248, + $this->database1(), + 'Profit', + [ + ['Tree', 'Height', 'Height'], + ['=Apple', '>10', '<16'], + ['=Pear', null, null], + ], + ], + [ + 1210000, + $this->database2(), + 'Sales', + [ + ['Quarter', 'Area'], + ['>2', 'North'], + ], + ], + /* + * We don't yet support woldcards in text search fields + [ + 710000, + $this->database2(), + 'Sales', + [ + ['Quarter', 'Sales Rep.'], + ['3', 'C*'], + ], + ], + */ + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php new file mode 100644 index 00000000..0436ea67 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php @@ -0,0 +1,101 @@ +database1(), + 'Yield', + [ + ['Tree'], + ['=Apple'], + ['=Pear'], + ], + ], + [ + 0.025622222222, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Math', 'Male'], + ], + ], + [ + 0.011622222222, + $this->database2(), + 'Score', + [ + ['Subject', 'Age'], + ['Science', '>8'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php new file mode 100644 index 00000000..467db2f2 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php @@ -0,0 +1,101 @@ +database1(), + 'Yield', + [ + ['Tree'], + ['=Apple'], + ['=Pear'], + ], + ], + [ + 0.038433333333, + $this->database2(), + 'Score', + [ + ['Subject', 'Gender'], + ['Math', 'Male'], + ], + ], + [ + 0.017433333333, + $this->database2(), + 'Score', + [ + ['Subject', 'Age'], + ['Science', '>8'], + ], + ], + [ + null, + $this->database1(), + null, + $this->database1(), + ], + ]; + } +} From 40a6dee0a42fb162c57d61bd729dff504249f337 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 22 Feb 2021 20:40:40 +0100 Subject: [PATCH 074/187] Enable support for dates and percentages in Excel Database functions (#1875) * Enable support for dates and percentages in Excel Database functions, and CountIf/AverageIf/etc * Enable support for booleans in Excel Database functions --- CHANGELOG.md | 1 + .../Calculation/Database/DatabaseAbstract.php | 7 ++-- src/PhpSpreadsheet/Calculation/Functions.php | 31 ++++++++++++++-- .../Functions/Database/DCountATest.php | 2 +- .../Functions/Database/DCountTest.php | 35 ++++++++++++++++++- .../Functions/Database/DProductTest.php | 3 -- .../Functions/Database/DSumTest.php | 2 +- 7 files changed, 68 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdeaaa8e..6c649844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Support for date values and percentages in query parameters for Database functions, and the IF expressions in functions like COUNTIF() and AVERAGEIF(). [#1875](https://github.com/PHPOffice/PhpSpreadsheet/pull/1875) - Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754) - Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) - Basic implementation of the PERMUTATIONA() Statistical Function diff --git a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php index 22ce0957..ae2c3fd7 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php +++ b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php @@ -83,8 +83,6 @@ abstract class DatabaseAbstract } /** - * @TODO Support for Dates (including handling for >, <=, etc) - * @TODO Suport for formatted numerics (e.g. '>12.5%' => '>0.125') * @TODO Suport for wildcard ? and * in strings (includng escaping) */ private static function buildQuery(array $criteriaNames, array $criteria): string @@ -121,7 +119,9 @@ abstract class DatabaseAbstract $testConditionList = $query; foreach ($criteriaNames as $key => $criteriaName) { $key = array_search($criteriaName, $fieldNames, true); - if (isset($dataValues[$key])) { + if (is_bool($dataValues[$key])) { + $dataValue = ($dataValues[$key]) ? 'TRUE' : 'FALSE'; + } elseif ($dataValues[$key] !== null) { $dataValue = $dataValues[$key]; $dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; } else { @@ -129,7 +129,6 @@ abstract class DatabaseAbstract } $testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList); } - // evaluate the criteria against the row data $result = Calculation::getInstance()->_calculateFormulaValue('=' . $testConditionList); // If the row failed to meet the criteria, remove it from the database diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index 2e8a7ecf..022e6be5 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use PhpOffice\PhpSpreadsheet\Cell\Cell; +use PhpOffice\PhpSpreadsheet\Shared\Date; class Functions { @@ -252,9 +253,11 @@ class Functions if ($condition === '') { $condition = '=""'; } - if (!is_string($condition) || !in_array($condition[0], ['>', '<', '='])) { - if (!is_numeric($condition)) { + $condition = self::operandSpecialHandling($condition); + if (is_bool($condition)) { + return '=' . ($condition ? 'TRUE' : 'FALSE'); + } elseif (!is_numeric($condition)) { $condition = Calculation::wrapResult(strtoupper($condition)); } @@ -263,9 +266,10 @@ class Functions preg_match('/(=|<[>=]?|>=?)(.*)/', $condition, $matches); [, $operator, $operand] = $matches; + $operand = self::operandSpecialHandling($operand); if (is_numeric(trim($operand, '"'))) { $operand = trim($operand, '"'); - } elseif (!is_numeric($operand)) { + } elseif (!is_numeric($operand) && $operand !== 'FALSE' && $operand !== 'TRUE') { $operand = str_replace('"', '""', $operand); $operand = Calculation::wrapResult(strtoupper($operand)); } @@ -273,6 +277,27 @@ class Functions return str_replace('""""', '""', $operator . $operand); } + private static function operandSpecialHandling($operand) + { + if (is_numeric($operand) || is_bool($operand)) { + return $operand; + } elseif (strtoupper($operand) === Calculation::getTRUE() || strtoupper($operand) === Calculation::getFALSE()) { + return strtoupper($operand); + } + + // Check for percentage + if (preg_match('/^\-?\d*\.?\d*\s?\%$/', $operand)) { + return ((float) rtrim($operand, '%')) / 100; + } + + // Check for dates + if (($dateValueOperand = Date::stringToExcel($operand)) !== false) { + return $dateValueOperand; + } + + return $operand; + } + /** * ERROR_TYPE. * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php index ea856c57..4cfea42f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php @@ -100,7 +100,7 @@ class DCountATest extends TestCase 'Score', [ ['Subject', 'Score'], - ['English', '>0.60'], + ['English', '>60%'], ], ], ]; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php index 9e12ac96..11d8adab 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php @@ -59,6 +59,21 @@ class DCountTest extends TestCase ]; } + protected function database3() + { + return [ + ['Status', 'Value'], + [false, 1], + [true, 2], + [true, 4], + [false, 8], + [true, 16], + [false, 32], + [false, 64], + [false, 128], + ]; + } + public function providerDCount() { return [ @@ -95,7 +110,25 @@ class DCountTest extends TestCase null, [ ['Subject', 'Score'], - ['English', '>0.63'], + ['English', '>63%'], + ], + ], + [ + 3, + $this->database3(), + 'Value', + [ + ['Status'], + [true], + ], + ], + [ + 5, + $this->database3(), + 'Value', + [ + ['Status'], + ['<>true'], ], ], ]; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php index 9b2f92b3..0fb1bba7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php @@ -73,8 +73,6 @@ class DProductTest extends TestCase ['=Pear', null, null], ], ], - /* - * We don't yet support date handling in the search query [ 36, $this->database2(), @@ -93,7 +91,6 @@ class DProductTest extends TestCase ['Test1', '<05-Jan-2017'], ], ], - */ [ null, $this->database1(), diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php index fbb86bb9..2a197cd1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php @@ -95,7 +95,7 @@ class DSumTest extends TestCase ], ], /* - * We don't yet support woldcards in text search fields + * We don't yet support wildcards in text search fields [ 710000, $this->database2(), From 25f7dcb9fd8fe437bbe524d55e78a65ac61094c8 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 23 Feb 2021 19:26:29 +0100 Subject: [PATCH 075/187] Enable support for wildcard text searches in Excel Database functions (#1876) * Enable support for wildcard text searches in Excel Database functions --- CHANGELOG.md | 1 + .../Calculation/Calculation.php | 11 ++- .../Calculation/Database/DatabaseAbstract.php | 69 ++++++++++++------- .../Calculation/Internal/MakeMatrix.php | 11 +++ .../Calculation/Internal/WildcardMatch.php | 34 +++++++++ .../Functions/Database/DSumTest.php | 3 - 6 files changed, 96 insertions(+), 33 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php create mode 100644 src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c649844..f8baacc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added - Support for date values and percentages in query parameters for Database functions, and the IF expressions in functions like COUNTIF() and AVERAGEIF(). [#1875](https://github.com/PHPOffice/PhpSpreadsheet/pull/1875) +- Support for booleans, and for wildcard text search in query parameters for Database functions. [#1876](https://github.com/PHPOffice/PhpSpreadsheet/pull/1876) - Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754) - Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) - Basic implementation of the PERMUTATIONA() Statistical Function diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 87bf44a5..ba629957 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -2663,12 +2663,16 @@ class Calculation private static $controlFunctions = [ 'MKMATRIX' => [ 'argumentCount' => '*', - 'functionCall' => [__CLASS__, 'mkMatrix'], + 'functionCall' => [Internal\MakeMatrix::class, 'make'], ], 'NAME.ERROR' => [ 'argumentCount' => '*', 'functionCall' => [Functions::class, 'NAME'], ], + 'WILDCARDMATCH' => [ + 'argumentCount' => '2', + 'functionCall' => [Internal\WildcardMatch::class, 'compare'], + ], ]; public function __construct(?Spreadsheet $spreadsheet = null) @@ -3742,11 +3746,6 @@ class Calculation return $formula; } - private static function mkMatrix(...$args) - { - return $args; - } - // Binary Operators // These operators always work on two values // Array key is the operator, the value indicates whether this is a left or right associative operator diff --git a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php index ae2c3fd7..a08f1251 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php +++ b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\Internal\WildcardMatch; abstract class DatabaseAbstract { @@ -82,9 +83,6 @@ abstract class DatabaseAbstract return $columnData; } - /** - * @TODO Suport for wildcard ? and * in strings (includng escaping) - */ private static function buildQuery(array $criteriaNames, array $criteria): string { $baseQuery = []; @@ -92,7 +90,7 @@ abstract class DatabaseAbstract foreach ($criterion as $field => $value) { $criterionName = $criteriaNames[$field]; if ($value !== null && $value !== '') { - $condition = '[:' . $criterionName . ']' . Functions::ifCondition($value); + $condition = self::buildCondition($value, $criterionName); $baseQuery[$key][] = $condition; } } @@ -108,31 +106,39 @@ abstract class DatabaseAbstract return (count($rowQuery) > 1) ? 'OR(' . implode(',', $rowQuery) . ')' : $rowQuery[0]; } - /** - * @param $criteriaNames - * @param $fieldNames - */ - private static function executeQuery(array $database, string $query, $criteriaNames, $fieldNames): array + private static function buildCondition($criterion, string $criterionName): string + { + $ifCondition = Functions::ifCondition($criterion); + + // Check for wildcard characters used in the condition + $result = preg_match('/(?[^"]*)(?".*[*?].*")/ui', $ifCondition, $matches); + if ($result !== 1) { + return "[:{$criterionName}]{$ifCondition}"; + } + + $trueFalse = ($matches['operator'] !== '<>'); + $wildcard = WildcardMatch::wildcard($matches['operand']); + $condition = "WILDCARDMATCH([:{$criterionName}],{$wildcard})"; + if ($trueFalse === false) { + $condition = "NOT({$condition})"; + } + + return $condition; + } + + private static function executeQuery(array $database, string $query, array $criteria, array $fields): array { foreach ($database as $dataRow => $dataValues) { // Substitute actual values from the database row for our [:placeholders] - $testConditionList = $query; - foreach ($criteriaNames as $key => $criteriaName) { - $key = array_search($criteriaName, $fieldNames, true); - if (is_bool($dataValues[$key])) { - $dataValue = ($dataValues[$key]) ? 'TRUE' : 'FALSE'; - } elseif ($dataValues[$key] !== null) { - $dataValue = $dataValues[$key]; - $dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; - } else { - $dataValue = 'NULL'; - } - $testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList); + $conditions = $query; + foreach ($criteria as $criterion) { + $conditions = self::processCondition($criterion, $fields, $dataValues, $conditions); } - // evaluate the criteria against the row data - $result = Calculation::getInstance()->_calculateFormulaValue('=' . $testConditionList); - // If the row failed to meet the criteria, remove it from the database + // evaluate the criteria against the row data + $result = Calculation::getInstance()->_calculateFormulaValue('=' . $conditions); + + // If the row failed to meet the criteria, remove it from the database if ($result !== true) { unset($database[$dataRow]); } @@ -140,4 +146,19 @@ abstract class DatabaseAbstract return $database; } + + private static function processCondition(string $criterion, array $fields, array $dataValues, string $conditions) + { + $key = array_search($criterion, $fields, true); + + $dataValue = 'NULL'; + if (is_bool($dataValues[$key])) { + $dataValue = ($dataValues[$key]) ? 'TRUE' : 'FALSE'; + } elseif ($dataValues[$key] !== null) { + $dataValue = $dataValues[$key]; + $dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; + } + + return str_replace('[:' . $criterion . ']', $dataValue, $conditions); + } } diff --git a/src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php b/src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php new file mode 100644 index 00000000..8b53464f --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php @@ -0,0 +1,11 @@ +2', 'North'], ], ], - /* - * We don't yet support wildcards in text search fields [ 710000, $this->database2(), @@ -105,7 +103,6 @@ class DSumTest extends TestCase ['3', 'C*'], ], ], - */ [ null, $this->database1(), From cb23cca3ecbc6177dbcd91c4f0a2a141166c722a Mon Sep 17 00:00:00 2001 From: oleibman Date: Sat, 27 Feb 2021 06:10:04 -0800 Subject: [PATCH 076/187] Avoid Duplicate Titles When Reading Multiple HTML Files (#1829) This issue arose while researching issue #1823. The issue was not a bug; it just required clarification to the author of how to use the software. But, while researching, I discovered that loading html into 2 sheets of a spreadsheet has a problem if the html title tag is the same for the 2 sheets. PhpSpreadsheet would be able to save the resulting file, but Excel would not be able to read it properly because of the duplicate title. The worksheet setTitle method allows for disambiguation is such a circumstance. The html reader passed a parameter indicating "don't disambiguate", but I can't see any harm in changing that to "disambiguate". An extremely simple fix, with tests to back it up. --- src/PhpSpreadsheet/Reader/Html.php | 2 +- .../Reader/Html/HtmlLoadStringTest.php | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index e1139015..09148d9f 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -320,7 +320,7 @@ class Html extends BaseReader { if ($child->nodeName === 'title') { $this->processDomElement($child, $sheet, $row, $column, $cellContent); - $sheet->setTitle($cellContent, true, false); + $sheet->setTitle($cellContent, true, true); $cellContent = ''; } else { $this->processDomElementSpanEtc($sheet, $row, $column, $cellContent, $child, $attributeArray); diff --git a/tests/PhpSpreadsheetTests/Reader/Html/HtmlLoadStringTest.php b/tests/PhpSpreadsheetTests/Reader/Html/HtmlLoadStringTest.php index e1041507..bc4c30ff 100644 --- a/tests/PhpSpreadsheetTests/Reader/Html/HtmlLoadStringTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Html/HtmlLoadStringTest.php @@ -89,4 +89,33 @@ class HtmlLoadStringTest extends TestCase $spreadsheet = $reader->loadFromString($html, $spreadsheet); self::assertEquals(2, $spreadsheet->getSheetCount()); } + + public function testCanLoadDuplicateTitle(): void + { + $html = <<<'EOF' + + +Sheet + + +
1
+ + +EOF; + $reader = new \PhpOffice\PhpSpreadsheet\Reader\Html(); + $spreadsheet = $reader->loadFromString($html); + $reader->setSheetIndex(1); + $reader->loadFromString($html, $spreadsheet); + $reader->setSheetIndex(2); + $reader->loadFromString($html, $spreadsheet); + $sheet = $spreadsheet->getSheet(0); + self::assertEquals(1, $sheet->getCell('A1')->getValue()); + self::assertEquals('Sheet', $sheet->getTitle()); + $sheet = $spreadsheet->getSheet(1); + self::assertEquals(1, $sheet->getCell('A1')->getValue()); + self::assertEquals('Sheet 1', $sheet->getTitle()); + $sheet = $spreadsheet->getSheet(2); + self::assertEquals(1, $sheet->getCell('A1')->getValue()); + self::assertEquals('Sheet 2', $sheet->getTitle()); + } } From 8dcdf581314a6a7ca729699e3e7858b5bbf0ec0f Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Sat, 27 Feb 2021 15:22:25 +0100 Subject: [PATCH 077/187] Update change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8baacc0..6dc53bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Nothing. ### Fixed +- Avoid Duplicate Titles When Reading Multiple HTML Files.[Issue #1823](https://github.com/PHPOffice/PhpSpreadsheet/issues/1823) [PR #1829](https://github.com/PHPOffice/PhpSpreadsheet/pull/1829) - Fixed issue with Worksheet's `getCell()` method when trying to get a cell by defined name. [#1858](https://github.com/PHPOffice/PhpSpreadsheet/issues/1858) - Fix possible endless loop in NumberFormat Masks [#1792](https://github.com/PHPOffice/PhpSpreadsheet/issues/1792) - Fix problem resulting from literal dot inside quotes in number format masks. [PR #1830](https://github.com/PHPOffice/PhpSpreadsheet/pull/1830) From 08673b5820b19dfff9ebb3597578f5e7f7e17422 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 27 Feb 2021 18:26:12 +0100 Subject: [PATCH 078/187] Initial experiments using the new Database query logic with Conditional Statistical Functions (#1880) - Refactoring of the Statistical Conditional functions (`AVERAGEIF()`, `AVERAGEIFS()`, `COUNTIF()`, `COUNTIFS()`, `MAXIFS()` and `MINIFS()` to use the new Database functions codebase. - Extended unit testing - Fix handling for null values - Fixes to wildcard text searches There's still scope for further improvements to memory usage and performance; but for now the code is stable with all unit tests passing --- CHANGELOG.md | 3 +- .../Calculation/Calculation.php | 12 +- src/PhpSpreadsheet/Calculation/Database.php | 2 +- .../Calculation/Database/DAverage.php | 2 +- .../Calculation/Database/DCountA.php | 2 +- .../Calculation/Database/DGet.php | 4 +- .../Calculation/Database/DatabaseAbstract.php | 30 ++- .../Calculation/Internal/WildcardMatch.php | 11 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 4 +- .../Calculation/Statistical.php | 241 +++--------------- .../Calculation/Statistical/Conditional.php | 234 +++++++++++++++++ src/PhpSpreadsheet/Worksheet/Worksheet.php | 28 +- .../Functions/Database/DCountATest.php | 5 - .../Functions/Database/DSumTest.php | 9 + .../Functions/Statistical/AverageIfsTest.php | 31 +++ .../PhpSpreadsheetTests/Helper/SampleTest.php | 3 + .../Calculation/Statistical/AVERAGEIF.php | 35 ++- .../Calculation/Statistical/AVERAGEIFS.php | 42 +++ .../data/Calculation/Statistical/COUNTIF.php | 47 +++- .../data/Calculation/Statistical/COUNTIFS.php | 23 +- tests/data/Calculation/Statistical/MAXIFS.php | 28 ++ tests/data/Calculation/Statistical/MINIFS.php | 28 ++ 22 files changed, 570 insertions(+), 254 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Conditional.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php create mode 100644 tests/data/Calculation/Statistical/AVERAGEIFS.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6dc53bd1..3ab843c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Implementation of the Excel `AVERAGEIFS()` functions as part of a restructuring of Database functions and Conditional Statistical functions. - Support for date values and percentages in query parameters for Database functions, and the IF expressions in functions like COUNTIF() and AVERAGEIF(). [#1875](https://github.com/PHPOffice/PhpSpreadsheet/pull/1875) -- Support for booleans, and for wildcard text search in query parameters for Database functions. [#1876](https://github.com/PHPOffice/PhpSpreadsheet/pull/1876) +- Support for booleans, and for wildcard text search in query parameters for Database functions, and the IF expressions in functions like COUNTIF() and AVERAGEIF(). [#1876](https://github.com/PHPOffice/PhpSpreadsheet/pull/1876) - Implemented DataBar for conditional formatting in Xlsx, providing read/write and creation of (type, value, direction, fills, border, axis position, color settings) as DataBar options in Excel. [#1754](https://github.com/PHPOffice/PhpSpreadsheet/pull/1754) - Alignment for ODS Writer [#1796](https://github.com/PHPOffice/PhpSpreadsheet/issues/1796) - Basic implementation of the PERMUTATIONA() Statistical Function diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index ba629957..e114a00d 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -343,12 +343,12 @@ class Calculation ], 'AVERAGEIF' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'AVERAGEIF'], + 'functionCall' => [Statistical\Conditional::class, 'AVERAGEIF'], 'argumentCount' => '2,3', ], 'AVERAGEIFS' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Conditional::class, 'AVERAGEIFS'], 'argumentCount' => '3+', ], 'BAHTTEXT' => [ @@ -639,12 +639,12 @@ class Calculation ], 'COUNTIF' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COUNTIF'], + 'functionCall' => [Statistical\Conditional::class, 'COUNTIF'], 'argumentCount' => '2', ], 'COUNTIFS' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COUNTIFS'], + 'functionCall' => [Statistical\Conditional::class, 'COUNTIFS'], 'argumentCount' => '2+', ], 'COUPDAYBS' => [ @@ -1630,7 +1630,7 @@ class Calculation ], 'MAXIFS' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MAXIFS'], + 'functionCall' => [Statistical\Conditional::class, 'MAXIFS'], 'argumentCount' => '3+', ], 'MDETERM' => [ @@ -1675,7 +1675,7 @@ class Calculation ], 'MINIFS' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MINIFS'], + 'functionCall' => [Statistical\Conditional::class, 'MINIFS'], 'argumentCount' => '3+', ], 'MINUTE' => [ diff --git a/src/PhpSpreadsheet/Calculation/Database.php b/src/PhpSpreadsheet/Calculation/Database.php index db16e2df..76431979 100644 --- a/src/PhpSpreadsheet/Calculation/Database.php +++ b/src/PhpSpreadsheet/Calculation/Database.php @@ -34,7 +34,7 @@ class Database * the column label in which you specify a condition for the * column. * - * @return float|string + * @return null|float|string */ public static function DAVERAGE($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DAverage.php b/src/PhpSpreadsheet/Calculation/Database/DAverage.php index 899b2426..ea45beda 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DAverage.php +++ b/src/PhpSpreadsheet/Calculation/Database/DAverage.php @@ -29,7 +29,7 @@ class DAverage extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DCountA.php b/src/PhpSpreadsheet/Calculation/Database/DCountA.php index 5e2ef110..1beaf012 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DCountA.php +++ b/src/PhpSpreadsheet/Calculation/Database/DCountA.php @@ -36,7 +36,7 @@ class DCountA extends DatabaseAbstract $field = self::fieldExtract($database, $field); return Statistical::COUNTA( - self::getFilteredColumn($database, $field, $criteria) + self::getFilteredColumn($database, $field ?? 0, $criteria) ); } } diff --git a/src/PhpSpreadsheet/Calculation/Database/DGet.php b/src/PhpSpreadsheet/Calculation/Database/DGet.php index 64858d9d..c2ffe302 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DGet.php +++ b/src/PhpSpreadsheet/Calculation/Database/DGet.php @@ -44,6 +44,8 @@ class DGet extends DatabaseAbstract return Functions::NAN(); } - return $columnData[0]; + $row = array_pop($columnData); + + return array_pop($row); } } diff --git a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php index a08f1251..2148ebc0 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php +++ b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php @@ -25,19 +25,20 @@ abstract class DatabaseAbstract * represents the position of the column within the list: 1 for * the first column, 2 for the second column, and so on. */ - protected static function fieldExtract(array $database, $field): ?string + protected static function fieldExtract(array $database, $field): ?int { $field = strtoupper(Functions::flattenSingleValue($field)); - $fieldNames = array_map('strtoupper', array_shift($database)); - - if (is_numeric($field)) { - $keys = array_keys($fieldNames); - - return $keys[$field - 1]; + if ($field === '') { + return null; } - $key = array_search($field, $fieldNames); - return $key ?: null; + $fieldNames = array_map('strtoupper', array_shift($database)); + if (is_numeric($field)) { + return ((int) $field) - 1; + } + $key = array_search($field, array_values($fieldNames), true); + + return ($key !== false) ? (int) $key : null; } /** @@ -70,14 +71,19 @@ abstract class DatabaseAbstract return self::executeQuery($database, $query, $criteriaNames, $fieldNames); } - protected static function getFilteredColumn(array $database, $field, array $criteria): array + protected static function getFilteredColumn(array $database, ?int $field, array $criteria): array { // reduce the database to a set of rows that match all the criteria $database = self::filter($database, $criteria); + $defaultReturnColumnValue = ($field === null) ? 1 : null; + // extract an array of values for the requested column $columnData = []; - foreach ($database as $row) { - $columnData[] = ($field !== null) ? $row[$field] : true; + foreach ($database as $rowKey => $row) { + $keys = array_keys($row); + $key = $keys[$field] ?? null; + $columnKey = $key ?? 'A'; + $columnData[$rowKey][$columnKey] = $row[$key] ?? $defaultReturnColumnValue; } return $columnData; diff --git a/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php b/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php index 5b4fe5b1..2ba20346 100644 --- a/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php +++ b/src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php @@ -5,9 +5,9 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Internal; class WildcardMatch { private const SEARCH_SET = [ - '/([^~])(\*)/ui', + '/(? $arg) { - if (!is_numeric($arg)) { - if ($conditionIsNumeric) { - continue; - } - $arg = Calculation::wrapResult(strtoupper($arg)); - } elseif (!$conditionIsNumeric) { - continue; - } - $testCondition = '=' . $arg . $condition; - if (Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - $returnValue += $averageArgs[$key]; - ++$aCount; - } - } - - if ($aCount > 0) { - return $returnValue / $aCount; - } - - return Functions::DIV0(); + return Statistical\Conditional::AVERAGEIF($range, $condition, $averageRange); } /** @@ -1137,38 +1111,21 @@ class Statistical * Counts the number of cells that contain numbers within the list of arguments * * Excel Function: - * COUNTIF(value1[,value2[, ...]],condition) + * COUNTIF(range,condition) * - * @param mixed $aArgs Data values + * @Deprecated 1.17.0 + * + * @see Statistical\Conditional::COUNTIF() + * Use the COUNTIF() method in the Statistical\Conditional class instead + * + * @param mixed $range Data values * @param string $condition the criteria that defines which cells will be counted * * @return int */ - public static function COUNTIF($aArgs, $condition) + public static function COUNTIF($range, $condition) { - $returnValue = 0; - - $aArgs = Functions::flattenArray($aArgs); - $condition = Functions::ifCondition($condition); - $conditionIsNumeric = strpos($condition, '"') === false; - // Loop through arguments - foreach ($aArgs as $arg) { - if (!is_numeric($arg)) { - if ($conditionIsNumeric) { - continue; - } - $arg = Calculation::wrapResult(strtoupper($arg)); - } elseif (!$conditionIsNumeric) { - continue; - } - $testCondition = '=' . $arg . $condition; - if (Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is it a value within our criteria - ++$returnValue; - } - } - - return $returnValue; + return Statistical\Conditional::COUNTIF($range, $condition); } /** @@ -1179,66 +1136,18 @@ class Statistical * Excel Function: * COUNTIFS(criteria_range1, criteria1, [criteria_range2, criteria2]…) * - * @param mixed $args Criterias + * @Deprecated 1.17.0 + * + * @see Statistical\Conditional::COUNTIFS() + * Use the COUNTIFS() method in the Statistical\Conditional class instead + * + * @param mixed $args Pairs of Ranges and Criteria * * @return int */ public static function COUNTIFS(...$args) { - $arrayList = $args; - - // Return value - $returnValue = 0; - - if (empty($arrayList)) { - return $returnValue; - } - - $aArgsArray = []; - $conditions = []; - - while (count($arrayList) > 0) { - $aArgsArray[] = Functions::flattenArray(array_shift($arrayList)); - $conditions[] = Functions::ifCondition(array_shift($arrayList)); - } - - // Loop through each arg and see if arguments and conditions are true - foreach (array_keys($aArgsArray[0]) as $index) { - $valid = true; - - foreach ($conditions as $cidx => $condition) { - $conditionIsNumeric = strpos($condition, '"') === false; - $arg = $aArgsArray[$cidx][$index]; - - // Loop through arguments - if (!is_numeric($arg)) { - if ($conditionIsNumeric) { - $valid = false; - - break; // if false found, don't need to check other conditions - } - $arg = Calculation::wrapResult(strtoupper($arg)); - } elseif (!$conditionIsNumeric) { - $valid = false; - - break; // if false found, don't need to check other conditions - } - $testCondition = '=' . $arg . $condition; - if (!Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is not a value within our criteria - $valid = false; - - break; // if false found, don't need to check other conditions - } - } - - if ($valid) { - ++$returnValue; - } - } - - // Return - return $returnValue; + return Statistical\Conditional::COUNTIFS(...$args); } /** @@ -2348,53 +2257,18 @@ class Statistical * Excel Function: * MAXIFS(max_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...) * + * @Deprecated 1.17.0 + * + * @see Statistical\Conditional::MAXIFS() + * Use the MAXIFS() method in the Statistical\Conditional class instead + * * @param mixed $args Data range and criterias * * @return float */ public static function MAXIFS(...$args) { - $arrayList = $args; - - // Return value - $returnValue = null; - - $maxArgs = Functions::flattenArray(array_shift($arrayList)); - $aArgsArray = []; - $conditions = []; - - while (count($arrayList) > 0) { - $aArgsArray[] = Functions::flattenArray(array_shift($arrayList)); - $conditions[] = Functions::ifCondition(array_shift($arrayList)); - } - - // Loop through each arg and see if arguments and conditions are true - foreach ($maxArgs as $index => $value) { - $valid = true; - - foreach ($conditions as $cidx => $condition) { - $arg = $aArgsArray[$cidx][$index]; - - // Loop through arguments - if (!is_numeric($arg)) { - $arg = Calculation::wrapResult(strtoupper($arg)); - } - $testCondition = '=' . $arg . $condition; - if (!Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is not a value within our criteria - $valid = false; - - break; // if false found, don't need to check other conditions - } - } - - if ($valid) { - $returnValue = $returnValue === null ? $value : max($value, $returnValue); - } - } - - // Return - return $returnValue; + return Conditional::MAXIFS(...$args); } /** @@ -2520,53 +2394,18 @@ class Statistical * Excel Function: * MINIFS(min_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...) * + * @Deprecated 1.17.0 + * + * @see Statistical\Conditional::MINIFS() + * Use the MINIFS() method in the Statistical\Conditional class instead + * * @param mixed $args Data range and criterias * * @return float */ public static function MINIFS(...$args) { - $arrayList = $args; - - // Return value - $returnValue = null; - - $minArgs = Functions::flattenArray(array_shift($arrayList)); - $aArgsArray = []; - $conditions = []; - - while (count($arrayList) > 0) { - $aArgsArray[] = Functions::flattenArray(array_shift($arrayList)); - $conditions[] = Functions::ifCondition(array_shift($arrayList)); - } - - // Loop through each arg and see if arguments and conditions are true - foreach ($minArgs as $index => $value) { - $valid = true; - - foreach ($conditions as $cidx => $condition) { - $arg = $aArgsArray[$cidx][$index]; - - // Loop through arguments - if (!is_numeric($arg)) { - $arg = Calculation::wrapResult(strtoupper($arg)); - } - $testCondition = '=' . $arg . $condition; - if (!Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is not a value within our criteria - $valid = false; - - break; // if false found, don't need to check other conditions - } - } - - if ($valid) { - $returnValue = $returnValue === null ? $value : min($value, $returnValue); - } - } - - // Return - return $returnValue; + return Conditional::MINIFS(...$args); } // diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php new file mode 100644 index 00000000..02bb0782 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php @@ -0,0 +1,234 @@ + 0) { + $conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]); + $database[] = array_merge( + [sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], + Functions::flattenArray(array_pop($args)) + ); + ++$pairCount; + } + + $conditions = array_map(null, ...$conditions); + $database = array_map(null, ...$database); + + return DCount::evaluate($database, null, $conditions); + } + + /** + * MAXIFS. + * + * Returns the maximum value within a range of cells that contain numbers within the list of arguments + * + * Excel Function: + * MAXIFS(max_range, criteria_range1, criteria1, [criteria_range2, criteria2]…) + * + * @param mixed $args Pairs of Ranges and Criteria + * + * @return null|float|string + */ + public static function MAXIFS(...$args) + { + if (empty($args)) { + return 0.0; + } + + $conditions = self::buildConditionSet(...$args); + $database = self::buildDatabase(...$args); + + return DMax::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); + } + + /** + * MINIFS. + * + * Returns the minimum value within a range of cells that contain numbers within the list of arguments + * + * Excel Function: + * MINIFS(min_range, criteria_range1, criteria1, [criteria_range2, criteria2]…) + * + * @param mixed $args Pairs of Ranges and Criteria + * + * @return null|float|string + */ + public static function MINIFS(...$args) + { + if (empty($args)) { + return 0.0; + } + + $conditions = self::buildConditionSet(...$args); + $database = self::buildDatabase(...$args); + + return DMin::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); + } + + private static function buildConditionSet(...$args): array + { + array_shift($args); + + $conditions = []; + $pairCount = 1; + while (count($args) > 0) { + $conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]); + array_pop($args); + ++$pairCount; + } + + if (count($conditions) === 1) { + return array_map( + function ($value) { + return [$value]; + }, + $conditions[0] + ); + } + + return array_map(null, ...$conditions); + } + + private static function buildDatabase(...$args): array + { + $database = []; + $database[] = array_merge( + [self::VALUE_COLUMN_NAME], + Functions::flattenArray(array_shift($args)) + ); + + $pairCount = 1; + while (count($args) > 0) { + array_pop($args); + $database[] = array_merge( + [sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], + Functions::flattenArray(array_pop($args)) + ); + ++$pairCount; + } + + return array_map(null, ...$database); + } +} diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 02305b7a..19119970 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -824,7 +824,7 @@ class Worksheet implements IComparable /** * Set title. * - * @param string $pValue String containing the dimension of this worksheet + * @param string $title String containing the dimension of this worksheet * @param bool $updateFormulaCellReferences Flag indicating whether cell references in formulae should * be updated to reflect the new sheet name. * This should be left as the default true, unless you are @@ -835,10 +835,10 @@ class Worksheet implements IComparable * * @return $this */ - public function setTitle($pValue, $updateFormulaCellReferences = true, $validate = true) + public function setTitle($title, $updateFormulaCellReferences = true, $validate = true) { // Is this a 'rename' or not? - if ($this->getTitle() == $pValue) { + if ($this->getTitle() == $title) { return $this; } @@ -847,37 +847,37 @@ class Worksheet implements IComparable if ($validate) { // Syntax check - self::checkSheetTitle($pValue); + self::checkSheetTitle($title); if ($this->parent) { // Is there already such sheet name? - if ($this->parent->sheetNameExists($pValue)) { + if ($this->parent->sheetNameExists($title)) { // Use name, but append with lowest possible integer - if (Shared\StringHelper::countCharacters($pValue) > 29) { - $pValue = Shared\StringHelper::substring($pValue, 0, 29); + if (Shared\StringHelper::countCharacters($title) > 29) { + $title = Shared\StringHelper::substring($title, 0, 29); } $i = 1; - while ($this->parent->sheetNameExists($pValue . ' ' . $i)) { + while ($this->parent->sheetNameExists($title . ' ' . $i)) { ++$i; if ($i == 10) { - if (Shared\StringHelper::countCharacters($pValue) > 28) { - $pValue = Shared\StringHelper::substring($pValue, 0, 28); + if (Shared\StringHelper::countCharacters($title) > 28) { + $title = Shared\StringHelper::substring($title, 0, 28); } } elseif ($i == 100) { - if (Shared\StringHelper::countCharacters($pValue) > 27) { - $pValue = Shared\StringHelper::substring($pValue, 0, 27); + if (Shared\StringHelper::countCharacters($title) > 27) { + $title = Shared\StringHelper::substring($title, 0, 27); } } } - $pValue .= " $i"; + $title .= " $i"; } } } // Set title - $this->title = $pValue; + $this->title = $title; $this->dirty = true; if ($this->parent && $this->parent->getCalculationEngine()) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php index 4cfea42f..f5214ed0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php @@ -80,10 +80,6 @@ class DCountATest extends TestCase ['Science', 'Male'], ], ], - /* - * Null value in datacolumn behaviour for DCOUNTA... will include not include a null value in the count - * if it is an actual cell value; but it will be included if it is a literal... this test case is - * currently passing literals [ 1, $this->database2(), @@ -93,7 +89,6 @@ class DCountATest extends TestCase ['Math', 'Female'], ], ], - */ [ 3, $this->database2(), diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php index 10915b3c..5c270fd2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php @@ -103,6 +103,15 @@ class DSumTest extends TestCase ['3', 'C*'], ], ], + [ + 705000, + $this->database2(), + 'Sales', + [ + ['Quarter', 'Sales Rep.'], + ['3', '<>C*'], + ], + ], [ null, $this->database1(), diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php new file mode 100644 index 00000000..84c53431 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php @@ -0,0 +1,31 @@ +getSamples() as $samples) { foreach ($samples as $sample) { +// if (array_pop(explode('/', $sample)) !== 'DGET.php') { +// continue; +// } if (!in_array($sample, $skipped)) { $file = 'samples/' . $sample; $result[] = [$file]; diff --git a/tests/data/Calculation/Statistical/AVERAGEIF.php b/tests/data/Calculation/Statistical/AVERAGEIF.php index 422a2771..736b833f 100644 --- a/tests/data/Calculation/Statistical/AVERAGEIF.php +++ b/tests/data/Calculation/Statistical/AVERAGEIF.php @@ -46,8 +46,39 @@ return [ '<2013', ], [ - 14000, - [7000, 14000, 'Hello World', 21000, 28000], + 200, + [7000, 14000, 21000, 28000], '<23000', + [100, 200, 300, 800], + ], + [ + (2 + 4 + 8) / 3, + [true, true, false, true, false], + true, + [2, 4, 6, 8, 10], + ], + [ + (6 + 10) / 2, + [true, true, false, true, false], + '<>true', + [2, 4, 6, 8, 10], + ], + [ + (1 + 2 + 5 + 6) / 4, + ['North', 'South', 'East', 'West', 'North', 'South', 'East', 'West'], + '???th', + [1, 2, 3, 4, 5, 6, 7, 8], + ], + [ + 16733.5, + ['East', 'West', 'North', 'South (New Office)', 'Midwest'], + '=*West', + [45678, 23789, -4789, 0, 9678], + ], + [ + 18589, + ['East', 'West', 'North', 'South (New Office)', 'Midwest'], + '<>*(New Office)', + [45678, 23789, -4789, 0, 9678], ], ]; diff --git a/tests/data/Calculation/Statistical/AVERAGEIFS.php b/tests/data/Calculation/Statistical/AVERAGEIFS.php new file mode 100644 index 00000000..6c94300c --- /dev/null +++ b/tests/data/Calculation/Statistical/AVERAGEIFS.php @@ -0,0 +1,42 @@ +70', + [75, 94, 86, 'incomplete'], + '<90', + ], + [ + '#DIV/0!', + [85, 80, 93, 75], + [85, 80, 93, 75], + '>95', + ], + [ + 87.5, + [87, 88, 'incomplete', 75], + [87, 88, 'incomplete', 75], + '<>incomplete', + [87, 88, 'incomplete', 75], + '>80', + ], + [ + 174000, + [223000, 125000, 456000, 322000, 340000, 198000, 310000, 250000, 460000, 261000, 389000, 305000], + [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], + 1, + ['North', 'North', 'South', 'North', 'North', 'South', 'North', 'North', 'South', 'North', 'North', 'South'], + 'North', + ], + [ + 285500, + [223000, 125000, 456000, 322000, 340000, 198000, 310000, 250000, 460000, 261000, 389000, 305000], + [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], + '>2', + ['Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol'], + 'Jeff', + ], +]; diff --git a/tests/data/Calculation/Statistical/COUNTIF.php b/tests/data/Calculation/Statistical/COUNTIF.php index c0e69c67..69277e72 100644 --- a/tests/data/Calculation/Statistical/COUNTIF.php +++ b/tests/data/Calculation/Statistical/COUNTIF.php @@ -23,12 +23,55 @@ return [ ], [ 2, - [6, 3, 4, 'X', ''], + [6, 3, 4, 'X', '', null], '<=4', ], [ 2, - [6, 3, 4, 'X', ''], + [6, 3, 4, 31, 'X', '', null], '<="4"', ], + [ + 2, + [0, 1, 1, 2, 3, 5, 8, 0, 13, 21], + 0, + ], + [ + 3, + [true, false, false, true, false, true, false, false], + true, + ], + [ + 5, + [true, false, false, true, false, true, false, false], + '<>true', + ], + [ + 4, + ['apples', 'oranges', 'peaches', 'apples'], + '*', + ], + [ + 3, + ['apples', 'oranges', 'peaches', 'apples'], + '*p*s*', + ], + [ + 4, + [ + ['apples', 'oranges', 'peaches', 'apples'], + ['bananas', 'mangoes', 'grapes', 'cherries'], + ], + '*p*e*', + ], + [ + 2, + ['apples', 'oranges', 'peaches', 'apples'], + '?????es', + ], + [ + 2, + ['great * ratings', 'bad * ratings', 'films * wars', 'films * trek', 'music * radio'], + '*~* ra*s', + ], ]; diff --git a/tests/data/Calculation/Statistical/COUNTIFS.php b/tests/data/Calculation/Statistical/COUNTIFS.php index 32f64d71..07f96d38 100644 --- a/tests/data/Calculation/Statistical/COUNTIFS.php +++ b/tests/data/Calculation/Statistical/COUNTIFS.php @@ -16,9 +16,28 @@ return [ ['C', 'B', 'A', 'B', 'B'], '=B', ], + // [ + // 2, + // [1, 2, 3, 'B', null, '', false], + // '<=2', + // ], + // [ + // 2, + // [1, 2, 3, 'B', null, '', false], + // '<=B', + // ], + [ + 4, + ['Female', 'Female', 'Female', 'Male', 'Male', 'Male', 'Female', 'Female', 'Female', 'Male', 'Male', 'Male'], + 'Female', + [0.63, 0.78, 0.39, 0.55, 0.71, 0.51, 0.78, 0.81, 0.49, 0.35, 0.69, 0.65], + '>60%', + ], [ 2, - [1, 2, 3, 'B', '', false], - '<=2', + ['Maths', 'English', 'Science', 'Maths', 'English', 'Science', 'Maths', 'English', 'Science', 'Maths', 'English', 'Science'], + 'Science', + [0.63, 0.78, 0.39, 0.55, 0.71, 0.51, 0.78, 0.81, 0.49, 0.35, 0.69, 0.65], + '<50%', ], ]; diff --git a/tests/data/Calculation/Statistical/MAXIFS.php b/tests/data/Calculation/Statistical/MAXIFS.php index deb4bceb..58ed5e46 100644 --- a/tests/data/Calculation/Statistical/MAXIFS.php +++ b/tests/data/Calculation/Statistical/MAXIFS.php @@ -21,6 +21,20 @@ return [ ], '=H', ], + [ + 2, + [ + [1], + [2], + [3], + ], + [ + ['Y'], + ['Y'], + ['N'], + ], + '=Y', + ], [ 2, [ @@ -41,4 +55,18 @@ return [ ], '=B', ], + [ + 456000, + [223000, 125000, 456000, 322000, 340000, 198000, 310000, 250000, 460000, 261000, 389000, 305000], + [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], + 1, + ], + [ + 310000, + [223000, 125000, 456000, 322000, 340000, 198000, 310000, 250000, 460000, 261000, 389000, 305000], + [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], + '>2', + ['Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol'], + 'Jeff', + ], ]; diff --git a/tests/data/Calculation/Statistical/MINIFS.php b/tests/data/Calculation/Statistical/MINIFS.php index a00f25b7..6ecade9f 100644 --- a/tests/data/Calculation/Statistical/MINIFS.php +++ b/tests/data/Calculation/Statistical/MINIFS.php @@ -21,6 +21,20 @@ return [ ], '=H', ], + [ + 1, + [ + [1], + [2], + [3], + ], + [ + ['Y'], + ['Y'], + ['N'], + ], + '=Y', + ], [ 2, [ @@ -41,4 +55,18 @@ return [ ], '=B', ], + [ + 125000, + [223000, 125000, 456000, 322000, 340000, 198000, 310000, 250000, 460000, 261000, 389000, 305000], + [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], + 1, + ], + [ + 261000, + [223000, 125000, 456000, 322000, 340000, 198000, 310000, 250000, 460000, 261000, 389000, 305000], + [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], + '>2', + ['Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol'], + 'Jeff', + ], ]; From 80a20fc9912eb4fc0cd010fa943038a9686af412 Mon Sep 17 00:00:00 2001 From: oleibman Date: Sat, 27 Feb 2021 11:43:22 -0800 Subject: [PATCH 079/187] 100% Coverage for Calculation/DateTime (#1870) * 100% Coverage for Calculation/DateTime The code in DateTime is now completely covered. Along the way, some errors were discovered and corrected. - The tests which have had to be changed at the start of every year are replaced by more robust equivalents which do not require annual changes. - Several places in the code where Gnumeric and OpenOffice were thought to differ from Excel do not appear to have had any justification. I have left a comment where such code has been removed. - Use DateTime when possible rather than date, time, or strftime functions to avoid potential Y2038 problems. - Some impossible code has been removed, replaced by an explanatory comment. - NETWORKDAYS had a bug when the start date was Sunday. There had been no tests of this condition. - Some functions allow boolean and null arguments where a number is expected. This is more complicated than the equivalent situations in MathTrig because the initial date for these calculations can be Day 1 rather than Day 0. - More testing for dates from 1900-01-01 through the fictitious everywhere-but-Excel 1900-01-29. - This showed that there is an additional Excel bug - Excel evaluates WEEKNUM(emptycell) as 0, which is not a valid result for WEEKNUM without a second argument. PhpSpreadsheet now duplicates this bug. - There is a similar and even worse bug for 1904-01-01 in 1904 calculations. Weeknum returns 0 for this, but returns the correct value for arguments of 0 or null. - DATEVALUE should accept 1900-02-29 (sigh) and relatives. PhpSpreadsheet now duplicates this bug. - Testing bootstrap sets default timezone. This appears to be a relic from the releases of PHP where the unwise decision, subsequenly reversed, was made to issue messages for "no default timezone is set" rather than just use a sensible default. This was a disruptive setting for some of the tests I added. There is only one test in the entire suite which is default-timezone-dependent. Setting and resetting of default timezone is moved to that test (Reader/ODS/ODSTest), and out of bootstrap. - There had been no testing of NOW() function. - DATEVALUE test had no tests for 1904 calendar and needs some. - DATE test changed 1900/1904 calendar in use without restoring it. - WEEKDAY test had no tests for 1904 calendar and needs some. - Which revealed a bug in Shared/Date (excelToDateTimeObject was not recognizing 1904-01-01 as valid when 1904 calendar is in use). - And an additional bug in that legal 1904-calendar values in the 0.0-1.0 range yielded the same "wrong" answers as 1900-calendar (see "One note" below). Also the comment for one of the calendar-1904 tests was wrong in attempting to identify what time of day the fraction represented. I had wanted to break this up into a set of smaller modules, a process already started for Engineering and MathTrig. However the number of source code changes was sufficient that I wanted a clean delta for this request. If it is merged, I will work on breaking it up afterwards. One note - Shared/Date/excelToDateTimeObject, when calendar-1900 is in use, returns an unexpected result if its argument is between 0 and 1, which is nominally invalid for that calendar. It uses a base-1970 calendar in that instance. That check is not justifiable for calendar-1904, where values in that range are legal, so I made the check specific to calendar-1900, and adjusted 3 1904 unit test results accordingly. However, I have to admit that I don't understand why that check should be made even for calendar-1900. It certainly doesn't match anything that Excel does. I would recommend scrapping that code altogether. If agreed, I would do this as part of the break-up into smaller modules. Another note - more controversially, it is clear that PhpSpreadsheet needs to support the Excel and PHP date formats. Although it requires further study, I am not convinced that it needs to support Unix timestamp format. Since that is a potential source of Y2038 problems on 32-bit systems, I would like to open a PR to deprecate the use of that format. Please let me know if you are aware of a valid reason to continue to support it. --- src/PhpSpreadsheet/Calculation/DateTime.php | 450 +++++++++--------- src/PhpSpreadsheet/Shared/Date.php | 2 +- .../Functions/DateTime/DateTest.php | 14 +- .../Functions/DateTime/DateValueTest.php | 40 +- .../Functions/DateTime/NowTest.php | 38 ++ .../Functions/DateTime/TimeTest.php | 32 +- .../Functions/DateTime/WeekDayTest.php | 20 +- .../Functions/DateTime/WeekNumTest.php | 22 +- .../Reader/Ods/OdsTest.php | 19 +- tests/bootstrap.php | 2 +- tests/data/Calculation/DateTime/DATEVALUE.php | 43 +- tests/data/Calculation/DateTime/DAY.php | 15 + .../data/Calculation/DateTime/ISOWEEKNUM.php | 10 + .../data/Calculation/DateTime/NETWORKDAYS.php | 18 + tests/data/Calculation/DateTime/WEEKDAY.php | 7 + tests/data/Calculation/DateTime/WEEKNUM.php | 27 ++ tests/data/Calculation/DateTime/WORKDAY.php | 16 + tests/data/Calculation/DateTime/YEARFRAC.php | 3 +- .../data/Shared/Date/ExcelToTimestamp1904.php | 8 +- 19 files changed, 536 insertions(+), 250 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php diff --git a/src/PhpSpreadsheet/Calculation/DateTime.php b/src/PhpSpreadsheet/Calculation/DateTime.php index 4c2b108a..64d72c2b 100644 --- a/src/PhpSpreadsheet/Calculation/DateTime.php +++ b/src/PhpSpreadsheet/Calculation/DateTime.php @@ -144,26 +144,10 @@ class DateTime */ public static function DATETIMENOW() { - $saveTimeZone = date_default_timezone_get(); - date_default_timezone_set('UTC'); - $retValue = false; - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - $retValue = (float) Date::PHPToExcel(time()); + $dti = new DateTimeImmutable(); + $dateArray = date_parse($dti->format('c')); - break; - case Functions::RETURNDATE_UNIX_TIMESTAMP: - $retValue = (int) time(); - - break; - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - $retValue = new \DateTime(); - - break; - } - date_default_timezone_set($saveTimeZone); - - return $retValue; + return is_array($dateArray) ? self::returnIn3FormatsArray($dateArray) : Functions::VALUE(); } /** @@ -185,27 +169,10 @@ class DateTime */ public static function DATENOW() { - $saveTimeZone = date_default_timezone_get(); - date_default_timezone_set('UTC'); - $retValue = false; - $excelDateTime = floor(Date::PHPToExcel(time())); - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - $retValue = (float) $excelDateTime; + $dti = new DateTimeImmutable(); + $dateArray = date_parse($dti->format('c')); - break; - case Functions::RETURNDATE_UNIX_TIMESTAMP: - $retValue = (int) Date::excelToTimestamp($excelDateTime); - - break; - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - $retValue = Date::excelToDateTimeObject($excelDateTime); - - break; - } - date_default_timezone_set($saveTimeZone); - - return $retValue; + return is_array($dateArray) ? self::returnIn3FormatsArray($dateArray, true) : Functions::VALUE(); } /** @@ -316,14 +283,8 @@ class DateTime // Execute function $excelDateValue = Date::formattedPHPToExcel($year, $month, $day); - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - return (float) $excelDateValue; - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) Date::excelToTimestamp($excelDateValue); - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - return Date::excelToDateTimeObject($excelDateValue); - } + + return self::returnIn3FormatsFloat($excelDateValue); } /** @@ -403,36 +364,24 @@ class DateTime } // Execute function - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - $date = 0; - $calendar = Date::getExcelCalendar(); - if ($calendar != Date::CALENDAR_WINDOWS_1900) { - $date = 1; - } + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_EXCEL) { + $date = 0; + $calendar = Date::getExcelCalendar(); + if ($calendar != Date::CALENDAR_WINDOWS_1900) { + $date = 1; + } - return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second); - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600 - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - $dayAdjust = 0; - if ($hour < 0) { - $dayAdjust = floor($hour / 24); - $hour = 24 - abs($hour % 24); - if ($hour == 24) { - $hour = 0; - } - } elseif ($hour >= 24) { - $dayAdjust = floor($hour / 24); - $hour = $hour % 24; - } - $phpDateObject = new \DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second); - if ($dayAdjust != 0) { - $phpDateObject->modify($dayAdjust . ' days'); - } - - return $phpDateObject; + return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second); } + if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { + return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600 + } + // RETURNDATE_PHP_DATETIME_OBJECT + // Hour has already been normalized (0-23) above + $phpDateObject = new \DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second); + + return $phpDateObject; } /** @@ -462,6 +411,8 @@ class DateTime */ public static function DATEVALUE($dateValue = 1) { + $dti = new DateTimeImmutable(); + $baseYear = Date::getExcelCalendar(); $dateValue = trim(Functions::flattenSingleValue($dateValue), '"'); // Strip any ordinals because they're allowed in Excel (English only) $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue); @@ -470,6 +421,7 @@ class DateTime $yearFound = false; $t1 = explode(' ', $dateValue); + $t = ''; foreach ($t1 as &$t) { if ((is_numeric($t)) && ($t > 31)) { if ($yearFound) { @@ -481,10 +433,11 @@ class DateTime $yearFound = true; } } - if ((count($t1) == 1) && (strpos($t, ':') !== false)) { + if (count($t1) === 1) { // We've been fed a time value without any date - return 0.0; - } elseif (count($t1) == 2) { + return ((strpos($t, ':') === false)) ? Functions::Value() : 0.0; + } + if (count($t1) == 2) { // We only have two parts of the date: either day/month or month/year if ($yearFound) { array_unshift($t1, 1); @@ -493,7 +446,7 @@ class DateTime $t1[1] += 1900; array_unshift($t1, 1); } else { - $t1[] = date('Y'); + $t1[] = $dti->format('Y'); } } } @@ -502,23 +455,13 @@ class DateTime $PHPDateArray = date_parse($dateValue); if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { + // If original count was 1, we've already returned. + // If it was 2, we added another. + // Therefore, neither of the first 2 stroks below can fail. $testVal1 = strtok($dateValue, '- '); - if ($testVal1 !== false) { - $testVal2 = strtok('- '); - if ($testVal2 !== false) { - $testVal3 = strtok('- '); - if ($testVal3 === false) { - $testVal3 = strftime('%Y'); - } - } else { - return Functions::VALUE(); - } - } else { - return Functions::VALUE(); - } - if ($testVal1 < 31 && $testVal2 < 12 && $testVal3 < 12 && strlen($testVal3) == 2) { - $testVal3 += 2000; - } + $testVal2 = strtok('- '); + $testVal3 = strtok('- ') ?: $dti->format('Y'); + self::adjustYear($testVal1, $testVal2, $testVal3); $PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3); if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { $PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3); @@ -528,44 +471,126 @@ class DateTime } } + $retValue = Functions::Value(); if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { // Execute function - if ($PHPDateArray['year'] == '') { - $PHPDateArray['year'] = strftime('%Y'); - } - if ($PHPDateArray['year'] < 1900) { + self::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y')); + if ($PHPDateArray['year'] < $baseYear) { return Functions::VALUE(); } - if ($PHPDateArray['month'] == '') { - $PHPDateArray['month'] = strftime('%m'); - } - if ($PHPDateArray['day'] == '') { - $PHPDateArray['day'] = strftime('%d'); - } - if (!checkdate($PHPDateArray['month'], $PHPDateArray['day'], $PHPDateArray['year'])) { - return Functions::VALUE(); - } - $excelDateValue = floor( - Date::formattedPHPToExcel( - $PHPDateArray['year'], - $PHPDateArray['month'], - $PHPDateArray['day'], - $PHPDateArray['hour'], - $PHPDateArray['minute'], - $PHPDateArray['second'] - ) - ); - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - return (float) $excelDateValue; - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) Date::excelToTimestamp($excelDateValue); - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - return new \DateTime($PHPDateArray['year'] . '-' . $PHPDateArray['month'] . '-' . $PHPDateArray['day'] . ' 00:00:00'); + self::replaceIfEmpty($PHPDateArray['month'], $dti->format('m')); + self::replaceIfEmpty($PHPDateArray['day'], $dti->format('d')); + $PHPDateArray['hour'] = 0; + $PHPDateArray['minute'] = 0; + $PHPDateArray['second'] = 0; + $month = (int) $PHPDateArray['month']; + $day = (int) $PHPDateArray['day']; + $year = (int) $PHPDateArray['year']; + if (!checkdate($month, $day, $year)) { + return ($year === 1900 && $month === 2 && $day === 29) ? self::returnIn3FormatsFloat(60.0) : Functions::VALUE(); } + $retValue = is_array($PHPDateArray) ? self::returnIn3FormatsArray($PHPDateArray, true) : Functions::VALUE(); } - return Functions::VALUE(); + return $retValue; + } + + /** + * Help reduce perceived complexity of some tests. + * + * @param mixed $value + * @param mixed $altValue + */ + private static function replaceIfEmpty(&$value, $altValue): void + { + $value = $value ?: $altValue; + } + + /** + * Adjust year in ambiguous situations. + */ + private static function adjustYear(string $testVal1, string $testVal2, string &$testVal3): void + { + if (!is_numeric($testVal1) || $testVal1 < 31) { + if (!is_numeric($testVal2) || $testVal2 < 12) { + if (is_numeric($testVal3) && $testVal3 < 12) { + $testVal3 += 2000; + } + } + } + } + + /** + * Return result in one of three formats. + * + * @return mixed + */ + private static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false) + { + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { + return new \DateTime( + $dateArray['year'] + . '-' . $dateArray['month'] + . '-' . $dateArray['day'] + . ' ' . $dateArray['hour'] + . ':' . $dateArray['minute'] + . ':' . $dateArray['second'] + ); + } + $excelDateValue = + Date::formattedPHPToExcel( + $dateArray['year'], + $dateArray['month'], + $dateArray['day'], + $dateArray['hour'], + $dateArray['minute'], + $dateArray['second'] + ); + if ($retType === Functions::RETURNDATE_EXCEL) { + return $noFrac ? floor($excelDateValue) : (float) $excelDateValue; + } + // RETURNDATE_UNIX_TIMESTAMP) + + return (int) Date::excelToTimestamp($excelDateValue); + } + + /** + * Return result in one of three formats. + * + * @return mixed + */ + private static function returnIn3FormatsFloat(float $excelDateValue) + { + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_EXCEL) { + return $excelDateValue; + } + if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { + return (int) Date::excelToTimestamp($excelDateValue); + } + // RETURNDATE_PHP_DATETIME_OBJECT + + return Date::excelToDateTimeObject($excelDateValue); + } + + /** + * Return result in one of three formats. + * + * @return mixed + */ + private static function returnIn3FormatsObject(\DateTime $PHPDateObject) + { + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { + return $PHPDateObject; + } + if ($retType === Functions::RETURNDATE_EXCEL) { + return (float) Date::PHPToExcel($PHPDateObject); + } + // RETURNDATE_UNIX_TIMESTAMP + + return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject)); } /** @@ -601,31 +626,22 @@ class DateTime } $PHPDateArray = date_parse($timeValue); + $retValue = Functions::VALUE(); if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - $excelDateValue = Date::formattedPHPToExcel( - $PHPDateArray['year'], - $PHPDateArray['month'], - $PHPDateArray['day'], - $PHPDateArray['hour'], - $PHPDateArray['minute'], - $PHPDateArray['second'] - ); - } else { - $excelDateValue = Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1; - } + // OpenOffice-specific code removed - it works just like Excel + $excelDateValue = Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1; - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - return (float) $excelDateValue; - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600; - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - return new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']); + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_EXCEL) { + $retValue = (float) $excelDateValue; + } elseif ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { + $retValue = (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600; + } else { + $retValue = new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']); } } - return Functions::VALUE(); + return $retValue; } /** @@ -980,7 +996,7 @@ class DateTime // Execute function $startDoW = 6 - self::WEEKDAY($startDate, 2); if ($startDoW < 0) { - $startDoW = 0; + $startDoW = 5; } $endDoW = self::WEEKDAY($endDate, 2); if ($endDoW >= 6) { @@ -1113,14 +1129,7 @@ class DateTime } } - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - return (float) $endDate; - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) Date::excelToTimestamp($endDate); - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - return Date::excelToDateTimeObject($endDate); - } + return self::returnIn3FormatsFloat($endDate); } /** @@ -1141,9 +1150,10 @@ class DateTime { $dateValue = Functions::flattenSingleValue($dateValue); - if ($dateValue === null) { - $dateValue = 1; - } elseif (is_string($dateValue = self::getDateValue($dateValue))) { + if ($dateValue === null || is_bool($dateValue)) { + return (int) $dateValue; + } + if (is_string($dateValue = self::getDateValue($dateValue))) { return Functions::VALUE(); } @@ -1170,7 +1180,7 @@ class DateTime * Excel Function: * WEEKDAY(dateValue[,style]) * - * @param int $dateValue Excel date serial value (float), PHP date timestamp (integer), + * @param float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string * @param int $style A number that determines the type of return value * 1 or omitted Numbers 1 (Sunday) through 7 (Saturday). @@ -1182,6 +1192,7 @@ class DateTime public static function WEEKDAY($dateValue = 1, $style = 1) { $dateValue = Functions::flattenSingleValue($dateValue); + self::nullFalseTrueToNumber($dateValue); $style = Functions::flattenSingleValue($style); if (!is_numeric($style)) { @@ -1191,19 +1202,19 @@ class DateTime } $style = floor($style); - if ($dateValue === null) { - $dateValue = 1; - } elseif (is_string($dateValue = self::getDateValue($dateValue))) { + $dateValue = self::getDateValue($dateValue); + if (is_string($dateValue)) { return Functions::VALUE(); - } elseif ($dateValue < 0.0) { + } + if ($dateValue < 0.0) { return Functions::NAN(); } // Execute function $PHPDateObject = Date::excelToDateTimeObject($dateValue); + self::silly1900($PHPDateObject); $DoW = (int) $PHPDateObject->format('w'); - $firstDay = 1; switch ($style) { case 1: ++$DoW; @@ -1219,20 +1230,10 @@ class DateTime if ($DoW === 0) { $DoW = 7; } - $firstDay = 0; --$DoW; break; } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) { - // Test for Excel's 1900 leap year, and introduce the error as required - if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) { - --$DoW; - if ($DoW < $firstDay) { - $DoW += 7; - } - } - } return $DoW; } @@ -1298,17 +1299,26 @@ class DateTime */ public static function WEEKNUM($dateValue = 1, $method = self::STARTWEEK_SUNDAY) { + $origDateValueNull = $dateValue === null; $dateValue = Functions::flattenSingleValue($dateValue); $method = Functions::flattenSingleValue($method); - if (!is_numeric($method)) { return Functions::VALUE(); } + $method = (int) $method; if (!array_key_exists($method, self::METHODARR)) { return Functions::NaN(); } $method = self::METHODARR[$method]; + if ($dateValue === null) { // boolean not allowed + // This seems to be an additional Excel bug. + if (self::buggyWeekNum1900($method)) { + return 0; + } + //$dateValue = 1; + $dateValue = (Date::getExcelCalendar() === DATE::CALENDAR_MAC_1904) ? 0 : 1; + } $dateValue = self::getDateValue($dateValue); if (is_string($dateValue)) { @@ -1321,8 +1331,14 @@ class DateTime // Execute function $PHPDateObject = Date::excelToDateTimeObject($dateValue); if ($method == self::STARTWEEK_MONDAY_ISO) { + self::silly1900($PHPDateObject); + return (int) $PHPDateObject->format('W'); } + if (self::buggyWeekNum1904($method, $origDateValueNull, $PHPDateObject)) { + return 0; + } + self::silly1900($PHPDateObject, '+ 5 years'); // 1905 calendar matches $dayOfYear = $PHPDateObject->format('z'); $PHPDateObject->modify('-' . $dayOfYear . ' days'); $firstDayOfFirstWeek = $PHPDateObject->format('w'); @@ -1334,6 +1350,18 @@ class DateTime return (int) $weekOfYear; } + private static function buggyWeekNum1900(int $method): bool + { + return $method === self::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_WINDOWS_1900; + } + + private static function buggyWeekNum1904(int $method, bool $origNull, \DateTime $dateObject): bool + { + // This appears to be another Excel bug. + + return $method === self::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_MAC_1904 && !$origNull && $dateObject->format('Y-m-d') === '1904-01-01'; + } + /** * ISOWEEKNUM. * @@ -1350,17 +1378,19 @@ class DateTime public static function ISOWEEKNUM($dateValue = 1) { $dateValue = Functions::flattenSingleValue($dateValue); + self::nullFalseTrueToNumber($dateValue); - if ($dateValue === null) { - $dateValue = 1; - } elseif (is_string($dateValue = self::getDateValue($dateValue))) { + $dateValue = self::getDateValue($dateValue); + if (!is_numeric($dateValue)) { return Functions::VALUE(); - } elseif ($dateValue < 0.0) { + } + if ($dateValue < 0.0) { return Functions::NAN(); } // Execute function $PHPDateObject = Date::excelToDateTimeObject($dateValue); + self::silly1900($PHPDateObject); return (int) $PHPDateObject->format('W'); } @@ -1449,12 +1479,7 @@ class DateTime $timeValue = Functions::flattenSingleValue($timeValue); if (!is_numeric($timeValue)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $testVal = strtok($timeValue, '/-: '); - if (strlen($testVal) < strlen($timeValue)) { - return Functions::VALUE(); - } - } + // Gnumeric test removed - it operates like Excel $timeValue = self::getTimeValue($timeValue); if (is_string($timeValue)) { return Functions::VALUE(); @@ -1490,12 +1515,7 @@ class DateTime $timeValue = $timeTester = Functions::flattenSingleValue($timeValue); if (!is_numeric($timeValue)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $testVal = strtok($timeValue, '/-: '); - if (strlen($testVal) < strlen($timeValue)) { - return Functions::VALUE(); - } - } + // Gnumeric test removed - it operates like Excel $timeValue = self::getTimeValue($timeValue); if (is_string($timeValue)) { return Functions::VALUE(); @@ -1531,12 +1551,7 @@ class DateTime $timeValue = Functions::flattenSingleValue($timeValue); if (!is_numeric($timeValue)) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $testVal = strtok($timeValue, '/-: '); - if (strlen($testVal) < strlen($timeValue)) { - return Functions::VALUE(); - } - } + // Gnumeric test removed - it operates like Excel $timeValue = self::getTimeValue($timeValue); if (is_string($timeValue)) { return Functions::VALUE(); @@ -1590,14 +1605,7 @@ class DateTime // Execute function $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths); - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - return (float) Date::PHPToExcel($PHPDateObject); - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject)); - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - return $PHPDateObject; - } + return self::returnIn3FormatsObject($PHPDateObject); } /** @@ -1639,13 +1647,31 @@ class DateTime $adjustDaysString = '-' . $adjustDays . ' days'; $PHPDateObject->modify($adjustDaysString); - switch (Functions::getReturnDateType()) { - case Functions::RETURNDATE_EXCEL: - return (float) Date::PHPToExcel($PHPDateObject); - case Functions::RETURNDATE_UNIX_TIMESTAMP: - return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject)); - case Functions::RETURNDATE_PHP_DATETIME_OBJECT: - return $PHPDateObject; + return self::returnIn3FormatsObject($PHPDateObject); + } + + /** + * Many functions accept null/false/true argument treated as 0/0/1. + * + * @param mixed $number + */ + private static function nullFalseTrueToNumber(&$number): void + { + $number = Functions::flattenSingleValue($number); + $baseYear = Date::getExcelCalendar(); + $nullVal = $baseYear === DATE::CALENDAR_MAC_1904 ? 0 : 1; + if ($number === null) { + $number = $nullVal; + } elseif (is_bool($number)) { + $number = $nullVal + (int) $number; + } + } + + private static function silly1900(\DateTime $PHPDateObject, string $mod = '-1 day'): void + { + $isoDate = $PHPDateObject->format('c'); + if ($isoDate < '1900-03-01') { + $PHPDateObject->modify($mod); } } } diff --git a/src/PhpSpreadsheet/Shared/Date.php b/src/PhpSpreadsheet/Shared/Date.php index 180a7159..28c39255 100644 --- a/src/PhpSpreadsheet/Shared/Date.php +++ b/src/PhpSpreadsheet/Shared/Date.php @@ -160,7 +160,7 @@ class Date { $timeZone = ($timeZone === null) ? self::getDefaultTimezone() : self::validateTimeZone($timeZone); if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) { - if ($excelTimestamp < 1.0) { + if ($excelTimestamp < 1 && self::$excelCalendar === self::CALENDAR_WINDOWS_1900) { // Unix timestamp base date $baseDate = new \DateTime('1970-01-01', $timeZone); } else { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php index 48f7cfd7..aad59729 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php @@ -9,11 +9,21 @@ use PHPUnit\Framework\TestCase; class DateTest extends TestCase { + private $returnDateType; + + private $excelCalendar; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->returnDateType = Functions::getReturnDateType(); + $this->excelCalendar = Date::getExcelCalendar(); Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + } + + protected function tearDown(): void + { + Functions::setReturnDateType($this->returnDateType); + Date::setExcelCalendar($this->excelCalendar); } /** diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php index 51e4f7c0..72e036f9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; +use DateTimeImmutable; use DateTimeInterface; use PhpOffice\PhpSpreadsheet\Calculation\DateTime; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -10,11 +11,21 @@ use PHPUnit\Framework\TestCase; class DateValueTest extends TestCase { + private $returnDateType; + + private $excelCalendar; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->returnDateType = Functions::getReturnDateType(); + $this->excelCalendar = Date::getExcelCalendar(); Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + } + + protected function tearDown(): void + { + Functions::setReturnDateType($this->returnDateType); + Date::setExcelCalendar($this->excelCalendar); } /** @@ -25,7 +36,21 @@ class DateValueTest extends TestCase */ public function testDATEVALUE($expectedResult, $dateValue): void { - $result = DateTime::DATEVALUE($dateValue); + // Loop to avoid extraordinarily rare edge case where first calculation + // and second do not take place on same day. + do { + $dtStart = new DateTimeImmutable(); + $startDay = $dtStart->format('d'); + if (is_string($expectedResult)) { + $replYMD = str_replace('Y', date('Y'), $expectedResult); + if ($replYMD !== $expectedResult) { + $expectedResult = DateTime::DATEVALUE($replYMD); + } + } + $result = DateTime::DATEVALUE($dateValue); + $dtEnd = new DateTimeImmutable(); + $endDay = $dtEnd->format('d'); + } while ($startDay !== $endDay); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } @@ -55,4 +80,13 @@ class DateValueTest extends TestCase // ... with the correct value self::assertEquals($result->format('d-M-Y'), '31-Jan-2012'); } + + public function testDATEVALUEwith1904Calendar(): void + { + Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + self::assertEquals(5428, DateTime::DATEVALUE('1918-11-11')); + self::assertEquals(0, DateTime::DATEVALUE('1904-01-01')); + self::assertEquals('#VALUE!', DateTime::DATEVALUE('1903-12-31')); + self::assertEquals('#VALUE!', DateTime::DATEVALUE('1900-02-29')); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php new file mode 100644 index 00000000..f139f703 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php @@ -0,0 +1,38 @@ +getActiveSheet(); + // Loop to avoid rare edge case where first calculation + // and second do not take place in same second. + do { + $dtStart = new DateTimeImmutable(); + $startSecond = $dtStart->format('s'); + $sheet->setCellValue('A1', '=NOW()'); + $dtEnd = new DateTimeImmutable(); + $endSecond = $dtEnd->format('s'); + } while ($startSecond !== $endSecond); + //echo("\n"); var_dump($sheet->getCell('A1')->getCalculatedValue()); echo ("\n"); + $sheet->setCellValue('B1', '=YEAR(A1)'); + $sheet->setCellValue('C1', '=MONTH(A1)'); + $sheet->setCellValue('D1', '=DAY(A1)'); + $sheet->setCellValue('E1', '=HOUR(A1)'); + $sheet->setCellValue('F1', '=MINUTE(A1)'); + $sheet->setCellValue('G1', '=SECOND(A1)'); + self::assertEquals($dtStart->format('Y'), $sheet->getCell('B1')->getCalculatedValue()); + self::assertEquals($dtStart->format('m'), $sheet->getCell('C1')->getCalculatedValue()); + self::assertEquals($dtStart->format('d'), $sheet->getCell('D1')->getCalculatedValue()); + self::assertEquals($dtStart->format('H'), $sheet->getCell('E1')->getCalculatedValue()); + self::assertEquals($dtStart->format('i'), $sheet->getCell('F1')->getCalculatedValue()); + self::assertEquals($dtStart->format('s'), $sheet->getCell('G1')->getCalculatedValue()); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php index 344061d4..3ef58374 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php @@ -9,11 +9,20 @@ use PHPUnit\Framework\TestCase; class TimeTest extends TestCase { + private $returnDateType; + + private $calendar; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + $this->returnDateType = Functions::getReturnDateType(); + $this->calendar = Date::getExcelCalendar(); + } + + protected function tearDown(): void + { + Functions::setReturnDateType($this->returnDateType); + Date::setExcelCalendar($this->calendar); } /** @@ -23,6 +32,7 @@ class TimeTest extends TestCase */ public function testTIME($expectedResult, ...$args): void { + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); $result = DateTime::TIME(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } @@ -52,4 +62,20 @@ class TimeTest extends TestCase // ... with the correct value self::assertEquals($result->format('H:i:s'), '07:30:20'); } + + public function testTIME1904(): void + { + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); + Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + $result = DateTime::TIME(0, 0, 0); + self::assertEquals(0, $result); + } + + public function testTIME1900(): void + { + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); + Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + $result = DateTime::TIME(0, 0, 0); + self::assertEquals(0, $result); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php index c5b89e01..99aa6f7c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php @@ -3,17 +3,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date; use PHPUnit\Framework\TestCase; class WeekDayTest extends TestCase { + private $excelCalendar; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + $this->excelCalendar = Date::getExcelCalendar(); + } + + protected function tearDown(): void + { + Date::setExcelCalendar($this->excelCalendar); } /** @@ -31,4 +35,12 @@ class WeekDayTest extends TestCase { return require 'tests/data/Calculation/DateTime/WEEKDAY.php'; } + + public function testWEEKDAYwith1904Calendar(): void + { + Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + self::assertEquals(7, DateTime::WEEKDAY('1904-01-02')); + self::assertEquals(6, DateTime::WEEKDAY('1904-01-01')); + self::assertEquals(6, DateTime::WEEKDAY(null)); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php index 9d8e1eb2..17119f28 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php @@ -3,17 +3,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date; use PHPUnit\Framework\TestCase; class WeekNumTest extends TestCase { + private $excelCalendar; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); + $this->excelCalendar = Date::getExcelCalendar(); + } + + protected function tearDown(): void + { + Date::setExcelCalendar($this->excelCalendar); } /** @@ -31,4 +35,14 @@ class WeekNumTest extends TestCase { return require 'tests/data/Calculation/DateTime/WEEKNUM.php'; } + + public function testWEEKNUMwith1904Calendar(): void + { + Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + self::assertEquals(27, DateTime::WEEKNUM('2004-07-02')); + self::assertEquals(1, DateTime::WEEKNUM('1904-01-02')); + self::assertEquals(1, DateTime::WEEKNUM(null)); + // The following is a bug in Excel. + self::assertEquals(0, DateTime::WEEKNUM('1904-01-01')); + } } diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php index 8be1aa7c..0160f68d 100644 --- a/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php @@ -15,6 +15,19 @@ use PHPUnit\Framework\TestCase; */ class OdsTest extends TestCase { + private $timeZone; + + protected function setUp(): void + { + $this->timeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + } + + protected function tearDown(): void + { + date_default_timezone_set($this->timeZone); + } + /** * @var Spreadsheet */ @@ -153,13 +166,13 @@ class OdsTest extends TestCase self::assertEquals(0, $firstSheet->getCell('G10')->getValue()); self::assertEquals(DataType::TYPE_NUMERIC, $firstSheet->getCell('A10')->getDataType()); // Date - self::assertEquals(22269.0, $firstSheet->getCell('A10')->getValue()); + self::assertEquals('19-Dec-60', $firstSheet->getCell('A10')->getFormattedValue()); self::assertEquals(DataType::TYPE_NUMERIC, $firstSheet->getCell('A13')->getDataType()); // Time - self::assertEquals(25569.0625, $firstSheet->getCell('A13')->getValue()); + self::assertEquals('2:30:00', $firstSheet->getCell('A13')->getFormattedValue()); self::assertEquals(DataType::TYPE_NUMERIC, $firstSheet->getCell('A15')->getDataType()); // Date + Time - self::assertEquals(22269.0625, $firstSheet->getCell('A15')->getValue()); + self::assertEquals('19-Dec-60 1:30:00', $firstSheet->getCell('A15')->getFormattedValue()); self::assertEquals(DataType::TYPE_NUMERIC, $firstSheet->getCell('A11')->getDataType()); // Fraction diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 77cd5228..9ebd3f26 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -3,4 +3,4 @@ setlocale(LC_ALL, 'en_US.utf8'); // PHP 5.3 Compat -date_default_timezone_set('Europe/London'); +//date_default_timezone_set('Europe/London'); diff --git a/tests/data/Calculation/DateTime/DATEVALUE.php b/tests/data/Calculation/DateTime/DATEVALUE.php index 17110c74..0b0f110f 100644 --- a/tests/data/Calculation/DateTime/DATEVALUE.php +++ b/tests/data/Calculation/DateTime/DATEVALUE.php @@ -20,12 +20,12 @@ return [ '1900/2/28', ], [ - '#VALUE!', + '60', '29-02-1900', ], // MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date [ - '#VALUE!', + '60', '29th February 1900', ], [ @@ -159,30 +159,32 @@ return [ '#VALUE!', 'The 1st day of March 2007', ], - // 01/01 of the current year + // Jan 1 of the current year [ - 44197, + 'Y-01-01', '1 Jan', ], - // 31/12 of the current year + // Dec 31 of the current year [ - 44561, + 'Y-12-31', '31/12', ], - // Excel reads as 1st December 1931, not 31st December in current year + // Excel reads as 1st December 1931, not 31st December in current year. + // This result is locale-dependent in Excel, in a manner not + // supported by PhpSpreadsheet. [ 11658, '12/31', ], - // 05/07 of the current year + // July 5 of the current year [ - 44382, + 'Y-07-05', '5-JUL', ], - // 05/07 of the current year + // July 5 of the current year [ - 44382, - '5 Jul', + 'Y-07-05', + '5 July', ], [ 39783, @@ -216,6 +218,11 @@ return [ '#VALUE!', 12, ], + // implicit day of month is 1 + [ + 40210, + 'Feb-2010', + ], [ 40221, '12-Feb-2010', @@ -294,4 +301,16 @@ return [ '#VALUE!', 'ABCDEFGHIJKMNOPQRSTUVWXYZ', ], + [ + '#VALUE!', + '1999', + ], + ['#VALUE!', '32/32'], + ['#VALUE!', '1910-'], + ['#VALUE!', '10--'], + ['#VALUE!', '--10'], + ['#VALUE!', '--1910'], + //['#VALUE!', '-JUL-1910'], We can parse this, Excel can't + ['#VALUE!', '2008-08-'], + [36751, '0-08-13'], ]; diff --git a/tests/data/Calculation/DateTime/DAY.php b/tests/data/Calculation/DateTime/DAY.php index 8ba4ad41..81fab933 100644 --- a/tests/data/Calculation/DateTime/DAY.php +++ b/tests/data/Calculation/DateTime/DAY.php @@ -53,4 +53,19 @@ return [ 30, // Result for OpenOffice 0, ], + [ + 0, // Result for Excel + 0, // Result for OpenOffice + null, + ], + [ + 1, // Result for Excel + 1, // Result for OpenOffice + true, + ], + [ + 0, // Result for Excel + 0, // Result for OpenOffice + false, + ], ]; diff --git a/tests/data/Calculation/DateTime/ISOWEEKNUM.php b/tests/data/Calculation/DateTime/ISOWEEKNUM.php index 78a4d3e8..b6afd303 100644 --- a/tests/data/Calculation/DateTime/ISOWEEKNUM.php +++ b/tests/data/Calculation/DateTime/ISOWEEKNUM.php @@ -33,4 +33,14 @@ return [ '#VALUE!', '1800-01-01', ], + ['52', null], + ['53', '1904-01-01'], + ['52', '1900-01-01'], + ['1', '1900-01-07'], + ['1', '1900-01-08'], + ['2', '1900-01-09'], + ['9', '1900-03-04'], + ['10', '1900-03-05'], + ['#NUM!', '-1'], + [39, '1000'], ]; diff --git a/tests/data/Calculation/DateTime/NETWORKDAYS.php b/tests/data/Calculation/DateTime/NETWORKDAYS.php index d62e501c..db548ddc 100644 --- a/tests/data/Calculation/DateTime/NETWORKDAYS.php +++ b/tests/data/Calculation/DateTime/NETWORKDAYS.php @@ -100,4 +100,22 @@ return [ '31-Jan-2007', '1-Feb-2007', ], + ['#VALUE!', 'ABQZ', '1-Feb-2007'], + ['#VALUE!', '1-Feb-2007', 'ABQZ'], + [10, '2021-02-13', '2021-02-27'], + [10, '2021-02-14', '2021-02-27'], + [3, '2021-02-14', '2021-02-17'], + [8, '2021-02-14', '2021-02-24'], + [9, '2021-02-14', '2021-02-25'], + [10, '2021-02-14', '2021-02-26'], + [9, '2021-02-13', '2021-02-25'], + [10, '2021-02-12', '2021-02-25'], + [ + '#VALUE!', + '10-Jan-1961', + '19-Dec-1960', + '25-Dec-1960', + 'ABQZ', + '01-Jan-1961', + ], ]; diff --git a/tests/data/Calculation/DateTime/WEEKDAY.php b/tests/data/Calculation/DateTime/WEEKDAY.php index 8cc68082..fadf11f7 100644 --- a/tests/data/Calculation/DateTime/WEEKDAY.php +++ b/tests/data/Calculation/DateTime/WEEKDAY.php @@ -110,4 +110,11 @@ return [ '#NUM!', -1, ], + [1, null], + [1, false], + [2, true], + [1, '1900-01-01'], + [7, '1900-01-01', 2], + [7, null, 2], + [7, '1900-02-05', 2], ]; diff --git a/tests/data/Calculation/DateTime/WEEKNUM.php b/tests/data/Calculation/DateTime/WEEKNUM.php index d73ee463..b109a534 100644 --- a/tests/data/Calculation/DateTime/WEEKNUM.php +++ b/tests/data/Calculation/DateTime/WEEKNUM.php @@ -173,4 +173,31 @@ return [ 1, '2025-12-29', 21, ], + ['9', '1900-03-01'], + ['2', '1900-01-07', 2], + ['2', '1905-01-07', 2], + ['1', '1900-01-01'], + ['1', '1900-01-01', 2], + ['2', '1900-01-02', 2], + ['1', null, 11], + ['1', null, 12], + ['1', null, 13], + ['1', null, 14], + ['1', null, 15], + ['1', null, 16], + ['0', null, 17], + ['1', '1905-01-01', 17], + ['0', null], + ['1', null, 2], + ['1', '1906-01-01'], + ['#VALUE!', true], + ['#VALUE!', false, 21], + ['52', null, 21], + ['53', '1904-01-01', 21], + ['52', '1900-01-01', 21], + ['1', '1900-01-07', 21], + ['1', '1900-01-08', 21], + ['2', '1900-01-09', 21], + ['9', '1900-03-04', 21], + ['10', '1900-03-05', 21], ]; diff --git a/tests/data/Calculation/DateTime/WORKDAY.php b/tests/data/Calculation/DateTime/WORKDAY.php index 76c517f9..fc5f6483 100644 --- a/tests/data/Calculation/DateTime/WORKDAY.php +++ b/tests/data/Calculation/DateTime/WORKDAY.php @@ -89,4 +89,20 @@ return [ ], ], ], + [ + 44242, + '15-Feb-2021', + 0, + ], + [ + '#VALUE!', + '5-Apr-2012', + 3, + [ + [ + '6-Apr-2012', + 'ABQZ', + ], + ], + ], ]; diff --git a/tests/data/Calculation/DateTime/YEARFRAC.php b/tests/data/Calculation/DateTime/YEARFRAC.php index 3e76087c..abdb71d9 100644 --- a/tests/data/Calculation/DateTime/YEARFRAC.php +++ b/tests/data/Calculation/DateTime/YEARFRAC.php @@ -559,5 +559,6 @@ return [ '2025-05-28', 1, ], - + ['#VALUE!', '2023-04-27', 'ABQZ', 1], + ['#VALUE!', 'ABQZ', '2023-04-07', 1], ]; diff --git a/tests/data/Shared/Date/ExcelToTimestamp1904.php b/tests/data/Shared/Date/ExcelToTimestamp1904.php index e0f30754..1c013ab4 100644 --- a/tests/data/Shared/Date/ExcelToTimestamp1904.php +++ b/tests/data/Shared/Date/ExcelToTimestamp1904.php @@ -29,17 +29,17 @@ return [ ], // 06:00:00 [ - 21600, + gmmktime(6, 0, 0, 1, 1, 1904), // 32-bit safe - no Y2038 problem 0.25, ], // 08:00.00 [ - 28800, + gmmktime(8, 0, 0, 1, 1, 1904), // 32-bit safe - no Y2038 problem 0.3333333333333333333, ], - // 02:57:46 + // 13:02:13 [ - 46933, + gmmktime(13, 02, 13, 1, 1, 1904), // 32-bit safe - no Y2038 problem 0.54321, ], ]; From 761c84a94693993b3192aea62805c6b0bbd55900 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 27 Feb 2021 23:10:33 +0100 Subject: [PATCH 080/187] Avoid the performance/memory overheads of "clone on modify" of $args (#1884) * Avoid the performance/memory overheads of "clone on modify" of $args when building the condition set/database for AVERAGEIFS(), MAXIFS() and MINIFS() * Avoid the performance/memory overheads of "clone on modify" of $args when building the condition set/database for COUNTIFS() --- .../Calculation/Statistical/Conditional.php | 76 +++++++++++-------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php index 02bb0782..ae334011 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php @@ -67,8 +67,8 @@ class Conditional return self::AVERAGEIF($args[2], $args[1], $args[0]); } - $conditions = self::buildConditionSet(...$args); - $database = self::buildDatabase(...$args); + $conditions = self::buildConditionSetForRange(...$args); + $database = self::buildDatabaseWithRange(...$args); return DAverage::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); } @@ -122,19 +122,8 @@ class Conditional return self::COUNTIF(...$args); } - $conditions = $database = []; - $pairCount = 1; - while (count($args) > 0) { - $conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]); - $database[] = array_merge( - [sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], - Functions::flattenArray(array_pop($args)) - ); - ++$pairCount; - } - - $conditions = array_map(null, ...$conditions); - $database = array_map(null, ...$database); + $database = self::buildDatabase(...$args); + $conditions = self::buildConditionSet(...$args); return DCount::evaluate($database, null, $conditions); } @@ -157,8 +146,8 @@ class Conditional return 0.0; } - $conditions = self::buildConditionSet(...$args); - $database = self::buildDatabase(...$args); + $conditions = self::buildConditionSetForRange(...$args); + $database = self::buildDatabaseWithRange(...$args); return DMax::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); } @@ -181,23 +170,22 @@ class Conditional return 0.0; } - $conditions = self::buildConditionSet(...$args); - $database = self::buildDatabase(...$args); + $conditions = self::buildConditionSetForRange(...$args); + $database = self::buildDatabaseWithRange(...$args); return DMin::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); } private static function buildConditionSet(...$args): array { - array_shift($args); + $conditions = self::buildConditions(1, ...$args); - $conditions = []; - $pairCount = 1; - while (count($args) > 0) { - $conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [array_pop($args)]); - array_pop($args); - ++$pairCount; - } + return array_map(null, ...$conditions); + } + + private static function buildConditionSetForRange(...$args): array + { + $conditions = self::buildConditions(2, ...$args); if (count($conditions) === 1) { return array_map( @@ -211,20 +199,46 @@ class Conditional return array_map(null, ...$conditions); } + private static function buildConditions(int $startOffset, ...$args): array + { + $conditions = []; + + $pairCount = 1; + $argumentCount = count($args); + for ($argument = $startOffset; $argument < $argumentCount; $argument += 2) { + $conditions[] = array_merge([sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], [$args[$argument]]); + ++$pairCount; + } + + return $conditions; + } + private static function buildDatabase(...$args): array + { + $database = []; + + return self::buildDataSet(0, $database, ...$args); + } + + private static function buildDatabaseWithRange(...$args): array { $database = []; $database[] = array_merge( [self::VALUE_COLUMN_NAME], - Functions::flattenArray(array_shift($args)) + Functions::flattenArray($args[0]) ); + return self::buildDataSet(1, $database, ...$args); + } + + private static function buildDataSet(int $startOffset, array $database, ...$args): array + { $pairCount = 1; - while (count($args) > 0) { - array_pop($args); + $argumentCount = count($args); + for ($argument = $startOffset; $argument < $argumentCount; $argument += 2) { $database[] = array_merge( [sprintf(self::CONDITIONAL_COLUMN_NAME, $pairCount)], - Functions::flattenArray(array_pop($args)) + Functions::flattenArray($args[$argument]) ); ++$pairCount; } From ee969fdcfe6c031a487375da3206915486b3e468 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 28 Feb 2021 10:24:33 +0100 Subject: [PATCH 081/187] Additional conditionals from math trig (#1885) * Use our new Conditional logic to implement the SUMIF() and SUMIFS() Mathematical functions --- samples/Basic/40_Duplicate_style.php | 2 +- .../Calculation/Calculation.php | 4 +- .../Calculation/Database/DatabaseAbstract.php | 4 + src/PhpSpreadsheet/Calculation/MathTrig.php | 93 ++++-------------- .../Calculation/Statistical/Conditional.php | 98 +++++++++++++++---- tests/data/Calculation/MathTrig/SUMIF.php | 18 ++++ tests/data/Calculation/MathTrig/SUMIFS.php | 19 ++++ .../Calculation/Statistical/AVERAGEIFS.php | 3 + .../data/Calculation/Statistical/COUNTIFS.php | 3 + tests/data/Calculation/Statistical/MAXIFS.php | 3 + tests/data/Calculation/Statistical/MINIFS.php | 3 + 11 files changed, 151 insertions(+), 99 deletions(-) diff --git a/samples/Basic/40_Duplicate_style.php b/samples/Basic/40_Duplicate_style.php index 0366703d..38f7fb49 100644 --- a/samples/Basic/40_Duplicate_style.php +++ b/samples/Basic/40_Duplicate_style.php @@ -30,7 +30,7 @@ for ($col = 1; $col <= 50; ++$col) { } } $d = microtime(true) - $t; -$helper->log('Add data (end) . time: ' . round((string) ($d . 2)) . ' s'); +$helper->log('Add data (end) . time: ' . (string) round($d, 2) . ' s'); // Save $helper->write($spreadsheet, __FILE__); diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index e114a00d..a3f45f19 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -2314,12 +2314,12 @@ class Calculation ], 'SUMIF' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMIF'], + 'functionCall' => [Statistical\Conditional::class, 'SUMIF'], 'argumentCount' => '2,3', ], 'SUMIFS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMIFS'], + 'functionCall' => [Statistical\Conditional::class, 'SUMIFS'], 'argumentCount' => '3+', ], 'SUMPRODUCT' => [ diff --git a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php index 2148ebc0..cf48bd88 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php +++ b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php @@ -162,6 +162,10 @@ abstract class DatabaseAbstract $dataValue = ($dataValues[$key]) ? 'TRUE' : 'FALSE'; } elseif ($dataValues[$key] !== null) { $dataValue = $dataValues[$key]; + // escape quotes if we have a string containing quotes + if (is_string($dataValue) && strpos($dataValue, '"') !== false) { + $dataValue = str_replace('"', '""', $dataValue); + } $dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index f12cc9df..5a966cbf 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -1284,44 +1284,22 @@ class MathTrig * Totals the values of cells that contain numbers within the list of arguments * * Excel Function: - * SUMIF(value1[,value2[, ...]],condition) + * SUMIF(range, criteria, [sum_range]) * - * @param mixed $aArgs Data values - * @param string $condition the criteria that defines which cells will be summed - * @param mixed $sumArgs + * @Deprecated 1.17.0 + * + * @see Statistical\Conditional::SUMIF() + * Use the SUMIF() method in the Statistical\Conditional class instead + * + * @param mixed $range Data values + * @param string $criteria the criteria that defines which cells will be summed + * @param mixed $sumRange * * @return float */ - public static function SUMIF($aArgs, $condition, $sumArgs = []) + public static function SUMIF($range, $criteria, $sumRange = []) { - $returnValue = 0; - - $aArgs = Functions::flattenArray($aArgs); - $sumArgs = Functions::flattenArray($sumArgs); - if (empty($sumArgs)) { - $sumArgs = $aArgs; - } - $condition = Functions::ifCondition($condition); - // Loop through arguments - foreach ($aArgs as $key => $arg) { - if (!is_numeric($arg)) { - $arg = str_replace('"', '""', $arg); - $arg = Calculation::wrapResult(strtoupper($arg)); - } - - $testCondition = '=' . $arg . $condition; - $sumValue = array_key_exists($key, $sumArgs) ? $sumArgs[$key] : 0; - - if ( - is_numeric($sumValue) && - Calculation::getInstance()->_calculateFormulaValue($testCondition) - ) { - // Is it a value within our criteria and only numeric can be added to the result - $returnValue += $sumValue; - } - } - - return $returnValue; + return Statistical\Conditional::SUMIF($range, $criteria, $sumRange); } /** @@ -1330,7 +1308,12 @@ class MathTrig * Totals the values of cells that contain numbers within the list of arguments * * Excel Function: - * SUMIFS(value1[,value2[, ...]],condition) + * SUMIFS(sum_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...) + * + * @Deprecated 1.17.0 + * + * @see Statistical\Conditional::SUMIFS() + * Use the SUMIFS() method in the Statistical\Conditional class instead * * @param mixed $args Data values * @@ -1338,47 +1321,7 @@ class MathTrig */ public static function SUMIFS(...$args) { - $arrayList = $args; - - // Return value - $returnValue = 0; - - $sumArgs = Functions::flattenArray(array_shift($arrayList)); - $aArgsArray = []; - $conditions = []; - - while (count($arrayList) > 0) { - $aArgsArray[] = Functions::flattenArray(array_shift($arrayList)); - $conditions[] = Functions::ifCondition(array_shift($arrayList)); - } - - // Loop through each sum and see if arguments and conditions are true - foreach ($sumArgs as $index => $value) { - $valid = true; - - foreach ($conditions as $cidx => $condition) { - $arg = $aArgsArray[$cidx][$index]; - - // Loop through arguments - if (!is_numeric($arg)) { - $arg = Calculation::wrapResult(strtoupper($arg)); - } - $testCondition = '=' . $arg . $condition; - if (!Calculation::getInstance()->_calculateFormulaValue($testCondition)) { - // Is not a value within our criteria - $valid = false; - - break; // if false found, don't need to check other conditions - } - } - - if ($valid) { - $returnValue += $value; - } - } - - // Return - return $returnValue; + return Statistical\Conditional::SUMIFS(...$args); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php index ae334011..7ed1e714 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php @@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Database\DAverage; use PhpOffice\PhpSpreadsheet\Calculation\Database\DCount; use PhpOffice\PhpSpreadsheet\Calculation\Database\DMax; use PhpOffice\PhpSpreadsheet\Calculation\Database\DMin; +use PhpOffice\PhpSpreadsheet\Calculation\Database\DSum; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Conditional @@ -30,18 +31,7 @@ class Conditional */ public static function AVERAGEIF($range, $condition, $averageRange = []) { - $range = Functions::flattenArray($range); - $averageRange = Functions::flattenArray($averageRange); - if (empty($averageRange)) { - $averageRange = $range; - } - - $database = array_map( - null, - array_merge([self::CONDITION_COLUMN_NAME], $range), - array_merge([self::VALUE_COLUMN_NAME], $averageRange) - ); - + $database = self::databaseFromRangeAndValue($range, $averageRange); $condition = [[self::CONDITION_COLUMN_NAME, self::VALUE_COLUMN_NAME], [$condition, null]]; return DAverage::evaluate($database, self::VALUE_COLUMN_NAME, $condition); @@ -64,11 +54,11 @@ class Conditional if (empty($args)) { return 0.0; } elseif (count($args) === 3) { - return self::AVERAGEIF($args[2], $args[1], $args[0]); + return self::AVERAGEIF($args[1], $args[2], $args[0]); } - $conditions = self::buildConditionSetForRange(...$args); - $database = self::buildDatabaseWithRange(...$args); + $conditions = self::buildConditionSetForValueRange(...$args); + $database = self::buildDatabaseWithValueRange(...$args); return DAverage::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); } @@ -146,8 +136,8 @@ class Conditional return 0.0; } - $conditions = self::buildConditionSetForRange(...$args); - $database = self::buildDatabaseWithRange(...$args); + $conditions = self::buildConditionSetForValueRange(...$args); + $database = self::buildDatabaseWithValueRange(...$args); return DMax::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); } @@ -170,12 +160,60 @@ class Conditional return 0.0; } - $conditions = self::buildConditionSetForRange(...$args); - $database = self::buildDatabaseWithRange(...$args); + $conditions = self::buildConditionSetForValueRange(...$args); + $database = self::buildDatabaseWithValueRange(...$args); return DMin::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); } + /** + * SUMIF. + * + * Totals the values of cells that contain numbers within the list of arguments + * + * Excel Function: + * SUMIF(range, criteria, [sum_range]) + * + * @param mixed $range Data values + * @param mixed $sumRange + * @param mixed $condition + * + * @return float + */ + public static function SUMIF($range, $condition, $sumRange = []) + { + $database = self::databaseFromRangeAndValue($range, $sumRange); + $condition = [[self::CONDITION_COLUMN_NAME, self::VALUE_COLUMN_NAME], [$condition, null]]; + + return DSum::evaluate($database, self::VALUE_COLUMN_NAME, $condition); + } + + /** + * SUMIFS. + * + * Counts the number of cells that contain numbers within the list of arguments + * + * Excel Function: + * SUMIFS(average_range, criteria_range1, criteria1, [criteria_range2, criteria2]…) + * + * @param mixed $args Pairs of Ranges and Criteria + * + * @return null|float|string + */ + public static function SUMIFS(...$args) + { + if (empty($args)) { + return 0.0; + } elseif (count($args) === 3) { + return self::SUMIF($args[1], $args[2], $args[0]); + } + + $conditions = self::buildConditionSetForValueRange(...$args); + $database = self::buildDatabaseWithValueRange(...$args); + + return DSum::evaluate($database, self::VALUE_COLUMN_NAME, $conditions); + } + private static function buildConditionSet(...$args): array { $conditions = self::buildConditions(1, ...$args); @@ -183,7 +221,7 @@ class Conditional return array_map(null, ...$conditions); } - private static function buildConditionSetForRange(...$args): array + private static function buildConditionSetForValueRange(...$args): array { $conditions = self::buildConditions(2, ...$args); @@ -220,7 +258,7 @@ class Conditional return self::buildDataSet(0, $database, ...$args); } - private static function buildDatabaseWithRange(...$args): array + private static function buildDatabaseWithValueRange(...$args): array { $database = []; $database[] = array_merge( @@ -245,4 +283,22 @@ class Conditional return array_map(null, ...$database); } + + private static function databaseFromRangeAndValue(array $range, array $valueRange = []): array + { + $range = Functions::flattenArray($range); + + $valueRange = Functions::flattenArray($valueRange); + if (empty($valueRange)) { + $valueRange = $range; + } + + $database = array_map( + null, + array_merge([self::CONDITION_COLUMN_NAME], $range), + array_merge([self::VALUE_COLUMN_NAME], $valueRange) + ); + + return $database; + } } diff --git a/tests/data/Calculation/MathTrig/SUMIF.php b/tests/data/Calculation/MathTrig/SUMIF.php index 4bd7fc4d..9cba4d15 100644 --- a/tests/data/Calculation/MathTrig/SUMIF.php +++ b/tests/data/Calculation/MathTrig/SUMIF.php @@ -120,4 +120,22 @@ return [ [5], ], ], + [ + 157559, + ['Jan', 'Jan', 'Jan', 'Jan', 'Feb', 'Feb', 'Feb', 'Feb'], + 'Feb', + [36693, 22100, 53321, 34440, 29889, 50090, 32080, 45500], + ], + [ + 66582, + ['North 1', 'North 2', 'South 1', 'South 2', 'North 1', 'North 2', 'South 1', 'South 2,'], + 'North 1', + [36693, 22100, 53321, 34440, 29889, 50090, 32080, 45500], + ], + [ + 138772, + ['North 1', 'North 2', 'South 1', 'South 2', 'North 1', 'North 2', 'South 1', 'South 2,'], + 'North ?', + [36693, 22100, 53321, 34440, 29889, 50090, 32080, 45500], + ], ]; diff --git a/tests/data/Calculation/MathTrig/SUMIFS.php b/tests/data/Calculation/MathTrig/SUMIFS.php index a374dd14..9d860c30 100644 --- a/tests/data/Calculation/MathTrig/SUMIFS.php +++ b/tests/data/Calculation/MathTrig/SUMIFS.php @@ -1,6 +1,9 @@ 2', + ['Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol', 'Jeff', 'Chris', 'Carol'], + 'Jeff', + ], ]; diff --git a/tests/data/Calculation/Statistical/AVERAGEIFS.php b/tests/data/Calculation/Statistical/AVERAGEIFS.php index 6c94300c..d5bc6dad 100644 --- a/tests/data/Calculation/Statistical/AVERAGEIFS.php +++ b/tests/data/Calculation/Statistical/AVERAGEIFS.php @@ -1,6 +1,9 @@ Date: Sun, 28 Feb 2021 13:18:51 +0100 Subject: [PATCH 082/187] Initial Formula Translation tests (#1886) * Initial Formula Translation tests --- samples/Basic/43_Merge_workbooks.php | 4 ++ .../Calculation/TranslationTest.php | 51 +++++++++++++++++++ tests/data/Calculation/Translations.php | 48 +++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Calculation/TranslationTest.php create mode 100644 tests/data/Calculation/Translations.php diff --git a/samples/Basic/43_Merge_workbooks.php b/samples/Basic/43_Merge_workbooks.php index 86314b3b..28353cc6 100644 --- a/samples/Basic/43_Merge_workbooks.php +++ b/samples/Basic/43_Merge_workbooks.php @@ -18,6 +18,10 @@ $helper->logRead('Xlsx', $filename2, $callStartTime); foreach ($spreadsheet2->getSheetNames() as $sheetName) { $sheet = $spreadsheet2->getSheetByName($sheetName); + if ($sheet === null) { + continue; + } + $sheet->setTitle($sheet->getTitle() . ' copied'); $spreadsheet1->addExternalSheet($sheet); } diff --git a/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php b/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php new file mode 100644 index 00000000..1eb66a0a --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php @@ -0,0 +1,51 @@ +compatibilityMode = Functions::getCompatibilityMode(); + $this->returnDate = Functions::getReturnDateType(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); + Functions::setReturnDateType($this->returnDate); + } + + /** + * @dataProvider providerTranslations + */ + public function testTranslation(string $expectedResult, string $locale, string $formula): void + { + $validLocale = Settings::setLocale($locale); + if (!$validLocale) { + self::markTestSkipped("Unable to set locale to {$locale}"); + } + + $translatedFormula = Calculation::getInstance()->_translateFormulaToLocale($formula); + self::assertSame($expectedResult, $translatedFormula); + + $restoredFormula = Calculation::getInstance()->_translateFormulaToEnglish($translatedFormula); + self::assertSame($formula, $restoredFormula); + } + + public function providerTranslations() + { + return require 'tests/data/Calculation/Translations.php'; + } +} diff --git a/tests/data/Calculation/Translations.php b/tests/data/Calculation/Translations.php new file mode 100644 index 00000000..d470a05c --- /dev/null +++ b/tests/data/Calculation/Translations.php @@ -0,0 +1,48 @@ + Date: Sun, 28 Feb 2021 09:58:57 -0700 Subject: [PATCH 083/187] Pdf Writer strtoupper() fix (#1629) * _setPageSize's strtoupper() on array argument PhpSpreadsheet/Writer/Pdf.php Class defines a protected static mixed array called $paperSizes, this array contains string values along with array values. 'strtoupper() expects parameter 1 to be string, array given' error happens due to array passed to $paperSize variable from that $paperSizes mixed array on the Mpdf Class where Pdf extends Examples of cases, when a 'Letter' paper size is chosen, then no problem occurs since the index in that value for the array is a string value, but when 'Tabloid' paper size is chosen the value in the index for that paper size is an array, that's when the strtoupper() error happens * _setPageSize's strtoupper() on array argument PhpSpreadsheet/Writer/Pdf.php Class defines a protected static mixed array called $paperSizes, this array contains string values along with array values. 'strtoupper() expects parameter 1 to be string, array given' error happens due to array passed to $paperSize variable from that $paperSizes mixed array on the Dompdf Class where Pdf extends Examples of cases; when a 'Letter' paper size is chosen, then no problem occurs since the index in the array for that value a string, but when 'Tabloid' paper size is chosen the value in the index for that paper size is an array, that's when the strtoupper() error happens. --- src/PhpSpreadsheet/Writer/Pdf/Dompdf.php | 2 +- src/PhpSpreadsheet/Writer/Pdf/Mpdf.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php b/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php index 9ae2ccee..87e8eeb5 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Dompdf.php @@ -59,7 +59,7 @@ class Dompdf extends Pdf // Create PDF $pdf = $this->createExternalWriterInstance(); - $pdf->setPaper(strtolower($paperSize), $orientation); + $pdf->setPaper($paperSize, $orientation); $pdf->loadHtml($this->generateHTMLAll()); $pdf->render(); diff --git a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php index 75e0010d..56ac6930 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php @@ -64,7 +64,7 @@ class Mpdf extends Pdf $config = ['tempDir' => $this->tempDir . '/mpdf']; $pdf = $this->createExternalWriterInstance($config); $ortmp = $orientation; - $pdf->_setPageSize(strtoupper($paperSize), $ortmp); + $pdf->_setPageSize($paperSize, $ortmp); $pdf->DefOrientation = $orientation; $pdf->AddPageByArray([ 'orientation' => $orientation, From 8721f795fc4537b2bdf9daf93e3b52c4805a214d Mon Sep 17 00:00:00 2001 From: Ivan Stanojevic Date: Mon, 1 Mar 2021 12:33:35 +0100 Subject: [PATCH 084/187] Update ReferenceHelper.php (#1873) * Update ReferenceHelper for Defined Names --- src/PhpSpreadsheet/ReferenceHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/ReferenceHelper.php b/src/PhpSpreadsheet/ReferenceHelper.php index 13f7cf71..513f0a53 100644 --- a/src/PhpSpreadsheet/ReferenceHelper.php +++ b/src/PhpSpreadsheet/ReferenceHelper.php @@ -608,7 +608,7 @@ class ReferenceHelper // Update workbook: define names if (count($pSheet->getParent()->getDefinedNames()) > 0) { foreach ($pSheet->getParent()->getDefinedNames() as $definedName) { - if ($definedName->getWorksheet()->getHashCode() === $pSheet->getHashCode()) { + if ($definedName->getWorksheet() !== null && $definedName->getWorksheet()->getHashCode() === $pSheet->getHashCode()) { $definedName->setValue($this->updateCellReference($definedName->getValue(), $pBefore, $pNumCols, $pNumRows)); } } From 2eaf9b53aa0625d4158f9a125a03fd16a01fce1a Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 2 Mar 2021 09:07:28 +0100 Subject: [PATCH 085/187] Start splitting some of the basic Statistical functions out into separate classes (#1888) * Start splitting some of the basic Statistical functions out into separate classes containing just a few similar functions * Splitting some of the basic Statistical functions out into separate classes containing just a few similar functions - MAX(), MAXA(), MIN() and MINA() * Splitting some more of the basic Statistical functions out into separate classes containing just a few similar functions - StandardDeviations and Variances --- .../Calculation/Calculation.php | 40 +- .../Calculation/Database/DAverage.php | 4 +- .../Calculation/Database/DCount.php | 4 +- .../Calculation/Database/DCountA.php | 4 +- .../Calculation/Database/DMax.php | 4 +- .../Calculation/Database/DMin.php | 4 +- .../Calculation/Database/DStDev.php | 4 +- .../Calculation/Database/DStDevP.php | 4 +- .../Calculation/Database/DVar.php | 4 +- .../Calculation/Database/DVarP.php | 4 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 18 +- .../Calculation/Statistical.php | 665 ++++-------------- .../Calculation/Statistical/AggregateBase.php | 50 ++ .../Calculation/Statistical/Averages.php | 137 ++++ .../Calculation/Statistical/Counts.php | 95 +++ .../Calculation/Statistical/MaxMinBase.php | 17 + .../Calculation/Statistical/Maximum.php | 78 ++ .../Calculation/Statistical/Minimum.php | 78 ++ .../Statistical/StandardDeviations.php | 181 +++++ .../Calculation/Statistical/VarianceBase.php | 26 + .../Calculation/Statistical/Variances.php | 183 +++++ src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php | 2 +- .../Functions/Statistical/StDevATest.php | 26 + .../Functions/Statistical/StDevPATest.php | 26 + .../Functions/Statistical/StDevPTest.php | 26 + .../Functions/Statistical/StDevTest.php | 26 + .../Functions/Statistical/VarATest.php | 26 + .../Functions/Statistical/VarPATest.php | 26 + .../Functions/Statistical/VarPTest.php | 26 + .../Functions/Statistical/VarTest.php | 26 + tests/data/Calculation/Statistical/STDEV.php | 12 + tests/data/Calculation/Statistical/STDEVA.php | 12 + tests/data/Calculation/Statistical/STDEVP.php | 12 + .../data/Calculation/Statistical/STDEVPA.php | 12 + tests/data/Calculation/Statistical/VAR.php | 8 + tests/data/Calculation/Statistical/VARA.php | 8 + tests/data/Calculation/Statistical/VARP.php | 8 + tests/data/Calculation/Statistical/VARPA.php | 8 + 38 files changed, 1314 insertions(+), 580 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/AggregateBase.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Averages.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Counts.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Maximum.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Minimum.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Variances.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php create mode 100644 tests/data/Calculation/Statistical/STDEV.php create mode 100644 tests/data/Calculation/Statistical/STDEVA.php create mode 100644 tests/data/Calculation/Statistical/STDEVP.php create mode 100644 tests/data/Calculation/Statistical/STDEVPA.php create mode 100644 tests/data/Calculation/Statistical/VAR.php create mode 100644 tests/data/Calculation/Statistical/VARA.php create mode 100644 tests/data/Calculation/Statistical/VARP.php create mode 100644 tests/data/Calculation/Statistical/VARPA.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index a3f45f19..bc0baa4d 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -328,17 +328,17 @@ class Calculation ], 'AVEDEV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'AVEDEV'], + 'functionCall' => [Statistical\Averages::class, 'AVEDEV'], 'argumentCount' => '1+', ], 'AVERAGE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'AVERAGE'], + 'functionCall' => [Statistical\Averages::class, 'AVERAGE'], 'argumentCount' => '1+', ], 'AVERAGEA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'AVERAGEA'], + 'functionCall' => [Statistical\Averages::class, 'AVERAGEA'], 'argumentCount' => '1+', ], 'AVERAGEIF' => [ @@ -624,17 +624,17 @@ class Calculation ], 'COUNT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COUNT'], + 'functionCall' => [Statistical\Counts::class, 'COUNT'], 'argumentCount' => '1+', ], 'COUNTA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COUNTA'], + 'functionCall' => [Statistical\Counts::class, 'COUNTA'], 'argumentCount' => '1+', ], 'COUNTBLANK' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COUNTBLANK'], + 'functionCall' => [Statistical\Counts::class, 'COUNTBLANK'], 'argumentCount' => '1', ], 'COUNTIF' => [ @@ -1620,12 +1620,12 @@ class Calculation ], 'MAX' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MAX'], + 'functionCall' => [Statistical\Maximum::class, 'MAX'], 'argumentCount' => '1+', ], 'MAXA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MAXA'], + 'functionCall' => [Statistical\Maximum::class, 'MAXA'], 'argumentCount' => '1+', ], 'MAXIFS' => [ @@ -1665,12 +1665,12 @@ class Calculation ], 'MIN' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MIN'], + 'functionCall' => [Statistical\Minimum::class, 'MIN'], 'argumentCount' => '1+', ], 'MINA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MINA'], + 'functionCall' => [Statistical\Minimum::class, 'MINA'], 'argumentCount' => '1+', ], 'MINIFS' => [ @@ -2263,22 +2263,22 @@ class Calculation ], 'STDEV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'STDEV'], + 'functionCall' => [Statistical\StandardDeviations::class, 'STDEV'], 'argumentCount' => '1+', ], 'STDEV.S' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'STDEV'], + 'functionCall' => [Statistical\StandardDeviations::class, 'STDEV'], 'argumentCount' => '1+', ], 'STDEV.P' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'STDEVP'], + 'functionCall' => [Statistical\StandardDeviations::class, 'STDEVP'], 'argumentCount' => '1+', ], 'STDEVA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'STDEVA'], + 'functionCall' => [Statistical\StandardDeviations::class, 'STDEVA'], 'argumentCount' => '1+', ], 'STDEVP' => [ @@ -2524,32 +2524,32 @@ class Calculation ], 'VAR' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'VARFunc'], + 'functionCall' => [Statistical\Variances::class, 'VAR'], 'argumentCount' => '1+', ], 'VAR.P' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'VARP'], + 'functionCall' => [Statistical\Variances::class, 'VARP'], 'argumentCount' => '1+', ], 'VAR.S' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'VARFunc'], + 'functionCall' => [Statistical\Variances::class, 'VAR'], 'argumentCount' => '1+', ], 'VARA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'VARA'], + 'functionCall' => [Statistical\Variances::class, 'VARA'], 'argumentCount' => '1+', ], 'VARP' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'VARP'], + 'functionCall' => [Statistical\Variances::class, 'VARP'], 'argumentCount' => '1+', ], 'VARPA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'VARPA'], + 'functionCall' => [Statistical\Variances::class, 'VARPA'], 'argumentCount' => '1+', ], 'VDB' => [ diff --git a/src/PhpSpreadsheet/Calculation/Database/DAverage.php b/src/PhpSpreadsheet/Calculation/Database/DAverage.php index ea45beda..738cb78e 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DAverage.php +++ b/src/PhpSpreadsheet/Calculation/Database/DAverage.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Averages; class DAverage extends DatabaseAbstract { @@ -38,7 +38,7 @@ class DAverage extends DatabaseAbstract return null; } - return Statistical::AVERAGE( + return Averages::AVERAGE( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DCount.php b/src/PhpSpreadsheet/Calculation/Database/DCount.php index da173c8c..bf41d6b5 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DCount.php +++ b/src/PhpSpreadsheet/Calculation/Database/DCount.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Counts; class DCount extends DatabaseAbstract { @@ -36,7 +36,7 @@ class DCount extends DatabaseAbstract { $field = self::fieldExtract($database, $field); - return Statistical::COUNT( + return Counts::COUNT( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DCountA.php b/src/PhpSpreadsheet/Calculation/Database/DCountA.php index 1beaf012..c48e53c5 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DCountA.php +++ b/src/PhpSpreadsheet/Calculation/Database/DCountA.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Counts; class DCountA extends DatabaseAbstract { @@ -35,7 +35,7 @@ class DCountA extends DatabaseAbstract { $field = self::fieldExtract($database, $field); - return Statistical::COUNTA( + return Counts::COUNTA( self::getFilteredColumn($database, $field ?? 0, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DMax.php b/src/PhpSpreadsheet/Calculation/Database/DMax.php index 8918c54d..6cf2f20d 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DMax.php +++ b/src/PhpSpreadsheet/Calculation/Database/DMax.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Maximum; class DMax extends DatabaseAbstract { @@ -39,7 +39,7 @@ class DMax extends DatabaseAbstract return null; } - return Statistical::MAX( + return Maximum::MAX( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DMin.php b/src/PhpSpreadsheet/Calculation/Database/DMin.php index 357c9a91..5668bcf6 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DMin.php +++ b/src/PhpSpreadsheet/Calculation/Database/DMin.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Minimum; class DMin extends DatabaseAbstract { @@ -39,7 +39,7 @@ class DMin extends DatabaseAbstract return null; } - return Statistical::MIN( + return Minimum::MIN( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DStDev.php b/src/PhpSpreadsheet/Calculation/Database/DStDev.php index 58bb4f7d..cfc7e952 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DStDev.php +++ b/src/PhpSpreadsheet/Calculation/Database/DStDev.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\StandardDeviations; class DStDev extends DatabaseAbstract { @@ -39,7 +39,7 @@ class DStDev extends DatabaseAbstract return null; } - return Statistical::STDEV( + return StandardDeviations::STDEV( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DStDevP.php b/src/PhpSpreadsheet/Calculation/Database/DStDevP.php index 0d2e050d..2a04c5d9 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DStDevP.php +++ b/src/PhpSpreadsheet/Calculation/Database/DStDevP.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\StandardDeviations; class DStDevP extends DatabaseAbstract { @@ -39,7 +39,7 @@ class DStDevP extends DatabaseAbstract return null; } - return Statistical::STDEVP( + return StandardDeviations::STDEVP( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DVar.php b/src/PhpSpreadsheet/Calculation/Database/DVar.php index 62c9f6c6..c70da073 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DVar.php +++ b/src/PhpSpreadsheet/Calculation/Database/DVar.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances; class DVar extends DatabaseAbstract { @@ -39,7 +39,7 @@ class DVar extends DatabaseAbstract return null; } - return Statistical::VARFunc( + return Variances::VAR( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DVarP.php b/src/PhpSpreadsheet/Calculation/Database/DVarP.php index 3a9744cb..f22f2cca 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DVarP.php +++ b/src/PhpSpreadsheet/Calculation/Database/DVarP.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Database; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances; class DVarP extends DatabaseAbstract { @@ -39,7 +39,7 @@ class DVarP extends DatabaseAbstract return null; } - return Statistical::VARP( + return Variances::VARP( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 5a966cbf..e72e24cd 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -1222,27 +1222,27 @@ class MathTrig $aArgs = self::filterFormulaArgs($cellReference, $aArgs); switch ($subtotal) { case 1: - return Statistical::AVERAGE($aArgs); + return Statistical\Averages::AVERAGE($aArgs); case 2: - return Statistical::COUNT($aArgs); + return Statistical\Counts::COUNT($aArgs); case 3: - return Statistical::COUNTA($aArgs); + return Statistical\Counts::COUNTA($aArgs); case 4: - return Statistical::MAX($aArgs); + return Statistical\Maximum::MAX($aArgs); case 5: - return Statistical::MIN($aArgs); + return Statistical\Minimum::MIN($aArgs); case 6: return self::PRODUCT($aArgs); case 7: - return Statistical::STDEV($aArgs); + return Statistical\StandardDeviations::STDEV($aArgs); case 8: - return Statistical::STDEVP($aArgs); + return Statistical\StandardDeviations::STDEVP($aArgs); case 9: return self::SUM($aArgs); case 10: - return Statistical::VARFunc($aArgs); + return Statistical\Variances::VAR($aArgs); case 11: - return Statistical::VARP($aArgs); + return Statistical\Variances::VARP($aArgs); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 2f695d5b..dc9c5b44 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2,8 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Averages; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Conditional; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Counts; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Maximum; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Minimum; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Permutations; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\StandardDeviations; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances; use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend; class Statistical @@ -520,48 +526,6 @@ class Statistical return Functions::NULL(); } - /** - * MS Excel does not count Booleans if passed as cell values, but they are counted if passed as literals. - * OpenOffice Calc always counts Booleans. - * Gnumeric never counts Booleans. - * - * @param mixed $arg - * @param mixed $k - * - * @return int|mixed - */ - private static function testAcceptedBoolean($arg, $k) - { - if ( - (is_bool($arg)) && - ((!Functions::isCellValue($k) && (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_EXCEL)) || - (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE)) - ) { - $arg = (int) $arg; - } - - return $arg; - } - - /** - * @param mixed $arg - * @param mixed $k - * - * @return bool - */ - private static function isAcceptedCountable($arg, $k) - { - if ( - ((is_numeric($arg)) && (!is_string($arg))) || - ((is_numeric($arg)) && (!Functions::isCellValue($k)) && - (Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_GNUMERIC)) - ) { - return true; - } - - return false; - } - /** * AVEDEV. * @@ -571,45 +535,18 @@ class Statistical * Excel Function: * AVEDEV(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Averages::AVEDEV() + * Use the AVEDEV() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string */ public static function AVEDEV(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - // Return value - $returnValue = 0; - - $aMean = self::AVERAGE(...$args); - if ($aMean === Functions::DIV0()) { - return Functions::NAN(); - } elseif ($aMean === Functions::VALUE()) { - return Functions::VALUE(); - } - - $aCount = 0; - foreach ($aArgs as $k => $arg) { - $arg = self::testAcceptedBoolean($arg, $k); - // Is it a numeric value? - // Strings containing numeric values are only counted if they are string literals (not cell values) - // and then only in MS Excel and in Open Office, not in Gnumeric - if ((is_string($arg)) && (!is_numeric($arg)) && (!Functions::isCellValue($k))) { - return Functions::VALUE(); - } - if (self::isAcceptedCountable($arg, $k)) { - $returnValue += abs($arg - $aMean); - ++$aCount; - } - } - - // Return - if ($aCount === 0) { - return Functions::DIV0(); - } - - return $returnValue / $aCount; + return Averages::AVEDEV(...$args); } /** @@ -620,35 +557,18 @@ class Statistical * Excel Function: * AVERAGE(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Averages::AVERAGE() + * Use the AVERAGE() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string */ public static function AVERAGE(...$args) { - $returnValue = $aCount = 0; - - // Loop through arguments - foreach (Functions::flattenArrayIndexed($args) as $k => $arg) { - $arg = self::testAcceptedBoolean($arg, $k); - // Is it a numeric value? - // Strings containing numeric values are only counted if they are string literals (not cell values) - // and then only in MS Excel and in Open Office, not in Gnumeric - if ((is_string($arg)) && (!is_numeric($arg)) && (!Functions::isCellValue($k))) { - return Functions::VALUE(); - } - if (self::isAcceptedCountable($arg, $k)) { - $returnValue += $arg; - ++$aCount; - } - } - - // Return - if ($aCount > 0) { - return $returnValue / $aCount; - } - - return Functions::DIV0(); + return Averages::AVERAGE(...$args); } /** @@ -659,39 +579,18 @@ class Statistical * Excel Function: * AVERAGEA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Averages::AVERAGEA() + * Use the AVERAGEA() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string */ public static function AVERAGEA(...$args) { - $returnValue = null; - - $aCount = 0; - // Loop through arguments - foreach (Functions::flattenArrayIndexed($args) as $k => $arg) { - if ( - (is_bool($arg)) && - (!Functions::isMatrixValue($k)) - ) { - } else { - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - $returnValue += $arg; - ++$aCount; - } - } - } - - if ($aCount > 0) { - return $returnValue / $aCount; - } - - return Functions::DIV0(); + return Averages::AVERAGEA(...$args); } /** @@ -715,7 +614,7 @@ class Statistical */ public static function AVERAGEIF($range, $condition, $averageRange = []) { - return Statistical\Conditional::AVERAGEIF($range, $condition, $averageRange); + return Conditional::AVERAGEIF($range, $condition, $averageRange); } /** @@ -1026,27 +925,18 @@ class Statistical * Excel Function: * COUNT(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Counts::COUNT() + * Use the COUNT() method in the Statistical\Counts class instead + * * @param mixed ...$args Data values * * @return int */ public static function COUNT(...$args) { - $returnValue = 0; - - // Loop through arguments - $aArgs = Functions::flattenArrayIndexed($args); - foreach ($aArgs as $k => $arg) { - $arg = self::testAcceptedBoolean($arg, $k); - // Is it a numeric value? - // Strings containing numeric values are only counted if they are string literals (not cell values) - // and then only in MS Excel and in Open Office, not in Gnumeric - if (self::isAcceptedCountable($arg, $k)) { - ++$returnValue; - } - } - - return $returnValue; + return Counts::COUNT(...$args); } /** @@ -1057,24 +947,18 @@ class Statistical * Excel Function: * COUNTA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Counts::COUNTA() + * Use the COUNTA() method in the Statistical\Counts class instead + * * @param mixed ...$args Data values * * @return int */ public static function COUNTA(...$args) { - $returnValue = 0; - - // Loop through arguments - $aArgs = Functions::flattenArrayIndexed($args); - foreach ($aArgs as $k => $arg) { - // Nulls are counted if literals, but not if cell values - if ($arg !== null || (!Functions::isCellValue($k))) { - ++$returnValue; - } - } - - return $returnValue; + return Counts::COUNTA(...$args); } /** @@ -1085,24 +969,18 @@ class Statistical * Excel Function: * COUNTBLANK(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Counts::COUNTBLANK() + * Use the COUNTBLANK() method in the Statistical\Counts class instead + * * @param mixed ...$args Data values * * @return int */ public static function COUNTBLANK(...$args) { - $returnValue = 0; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a blank cell? - if (($arg === null) || ((is_string($arg)) && ($arg == ''))) { - ++$returnValue; - } - } - - return $returnValue; + return Counts::COUNTBLANK(...$args); } /** @@ -1125,7 +1003,7 @@ class Statistical */ public static function COUNTIF($range, $condition) { - return Statistical\Conditional::COUNTIF($range, $condition); + return Conditional::COUNTIF($range, $condition); } /** @@ -1147,7 +1025,7 @@ class Statistical */ public static function COUNTIFS(...$args) { - return Statistical\Conditional::COUNTIFS(...$args); + return Conditional::COUNTIFS(...$args); } /** @@ -1325,7 +1203,7 @@ class Statistical // Return value $returnValue = null; - $aMean = self::AVERAGE($aArgs); + $aMean = Averages::AVERAGE($aArgs); if ($aMean != Functions::DIV0()) { $aCount = -1; foreach ($aArgs as $k => $arg) { @@ -1711,8 +1589,8 @@ class Statistical $aMean = MathTrig::PRODUCT($aArgs); if (is_numeric($aMean) && ($aMean > 0)) { - $aCount = self::COUNT($aArgs); - if (self::MIN($aArgs) > 0) { + $aCount = Counts::COUNT($aArgs); + if (Minimum::MIN($aArgs) > 0) { return $aMean ** (1 / $aCount); } } @@ -1772,7 +1650,7 @@ class Statistical // Loop through arguments $aArgs = Functions::flattenArray($args); - if (self::MIN($aArgs) < 0) { + if (Minimum::MIN($aArgs) < 0) { return Functions::NAN(); } $aCount = 0; @@ -1883,8 +1761,8 @@ class Statistical public static function KURT(...$args) { $aArgs = Functions::flattenArrayIndexed($args); - $mean = self::AVERAGE($aArgs); - $stdDev = self::STDEV($aArgs); + $mean = Averages::AVERAGE($aArgs); + $stdDev = StandardDeviations::STDEV($aArgs); if ($stdDev > 0) { $count = $summer = 0; @@ -1941,7 +1819,7 @@ class Statistical $mArgs[] = $arg; } } - $count = self::COUNT($mArgs); + $count = Counts::COUNT($mArgs); --$entry; if (($entry < 0) || ($entry >= $count) || ($count == 0)) { return Functions::NAN(); @@ -2184,30 +2062,18 @@ class Statistical * Excel Function: * MAX(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Maximum::MAX() + * Use the MAX() method in the Statistical\Maximum class instead + * * @param mixed ...$args Data values * * @return float */ public static function MAX(...$args) { - $returnValue = null; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (($returnValue === null) || ($arg > $returnValue)) { - $returnValue = $arg; - } - } - } - - if ($returnValue === null) { - return 0; - } - - return $returnValue; + return Maximum::MAX(...$args); } /** @@ -2218,35 +2084,18 @@ class Statistical * Excel Function: * MAXA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Maximum::MAXA() + * Use the MAXA() method in the Statistical\Maximum class instead + * * @param mixed ...$args Data values * * @return float */ public static function MAXA(...$args) { - $returnValue = null; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if (($returnValue === null) || ($arg > $returnValue)) { - $returnValue = $arg; - } - } - } - - if ($returnValue === null) { - return 0; - } - - return $returnValue; + return Maximum::MAXA(...$args); } /** @@ -2321,30 +2170,18 @@ class Statistical * Excel Function: * MIN(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Minimum::MIN() + * Use the MIN() method in the Statistical\Minimum class instead + * * @param mixed ...$args Data values * * @return float */ public static function MIN(...$args) { - $returnValue = null; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if (($returnValue === null) || ($arg < $returnValue)) { - $returnValue = $arg; - } - } - } - - if ($returnValue === null) { - return 0; - } - - return $returnValue; + return Minimum::MIN(...$args); } /** @@ -2355,35 +2192,18 @@ class Statistical * Excel Function: * MINA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Minimum::MINA() + * Use the MINA() method in the Statistical\Minimum class instead + * * @param mixed ...$args Data values * * @return float */ public static function MINA(...$args) { - $returnValue = null; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if (($returnValue === null) || ($arg < $returnValue)) { - $returnValue = $arg; - } - } - } - - if ($returnValue === null) { - return 0; - } - - return $returnValue; + return Minimum::MINA(...$args); } /** @@ -2688,7 +2508,7 @@ class Statistical $mValueCount = count($mArgs); if ($mValueCount > 0) { sort($mArgs); - $count = self::COUNT($mArgs); + $count = Counts::COUNT($mArgs); $index = $entry * ($count - 1); $iBase = floor($index); if ($index == $iBase) { @@ -2775,7 +2595,7 @@ class Statistical */ public static function PERMUT($numObjs, $numInSet) { - return Statistical\Permutations::PERMUT($numObjs, $numInSet); + return Permutations::PERMUT($numObjs, $numInSet); } /** @@ -2930,8 +2750,8 @@ class Statistical public static function SKEW(...$args) { $aArgs = Functions::flattenArrayIndexed($args); - $mean = self::AVERAGE($aArgs); - $stdDev = self::STDEV($aArgs); + $mean = Averages::AVERAGE($aArgs); + $stdDev = StandardDeviations::STDEV($aArgs); $count = $summer = 0; // Loop through arguments @@ -3015,7 +2835,7 @@ class Statistical $mArgs[] = $arg; } } - $count = self::COUNT($mArgs); + $count = Counts::COUNT($mArgs); --$entry; if (($entry < 0) || ($entry >= $count) || ($count == 0)) { return Functions::NAN(); @@ -3065,45 +2885,18 @@ class Statistical * Excel Function: * STDEV(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\StandardDeviations::STDEV() + * Use the STDEV() method in the Statistical\StandardDeviations class instead + * * @param mixed ...$args Data values * * @return float|string The result, or a string containing an error */ public static function STDEV(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - // Return value - $returnValue = null; - - $aMean = self::AVERAGE($aArgs); - if ($aMean !== null) { - $aCount = -1; - foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) - ) { - $arg = (int) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ($returnValue === null) { - $returnValue = ($arg - $aMean) ** 2; - } else { - $returnValue += ($arg - $aMean) ** 2; - } - ++$aCount; - } - } - - // Return - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - - return Functions::DIV0(); + return StandardDeviations::STDEV(...$args); } /** @@ -3114,48 +2907,18 @@ class Statistical * Excel Function: * STDEVA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\StandardDeviations::STDEVA() + * Use the STDEVA() method in the Statistical\StandardDeviations class instead + * * @param mixed ...$args Data values * * @return float|string */ public static function STDEVA(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $returnValue = null; - - $aMean = self::AVERAGEA($aArgs); - if ($aMean !== null) { - $aCount = -1; - foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - (!Functions::isMatrixValue($k)) - ) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if ($returnValue === null) { - $returnValue = ($arg - $aMean) ** 2; - } else { - $returnValue += ($arg - $aMean) ** 2; - } - ++$aCount; - } - } - } - - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - - return Functions::DIV0(); + return StandardDeviations::STDEVA(...$args); } /** @@ -3166,43 +2929,18 @@ class Statistical * Excel Function: * STDEVP(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\StandardDeviations::STDEVP() + * Use the STDEVP() method in the Statistical\StandardDeviations class instead + * * @param mixed ...$args Data values * * @return float|string */ public static function STDEVP(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $returnValue = null; - - $aMean = self::AVERAGE($aArgs); - if ($aMean !== null) { - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) - ) { - $arg = (int) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ($returnValue === null) { - $returnValue = ($arg - $aMean) ** 2; - } else { - $returnValue += ($arg - $aMean) ** 2; - } - ++$aCount; - } - } - - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - - return Functions::DIV0(); + return StandardDeviations::STDEVP(...$args); } /** @@ -3213,48 +2951,18 @@ class Statistical * Excel Function: * STDEVPA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\StandardDeviations::STDEVPA() + * Use the STDEVPA() method in the Statistical\StandardDeviations class instead + * * @param mixed ...$args Data values * * @return float|string */ public static function STDEVPA(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $returnValue = null; - - $aMean = self::AVERAGEA($aArgs); - if ($aMean !== null) { - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - (!Functions::isMatrixValue($k)) - ) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - if ($returnValue === null) { - $returnValue = ($arg - $aMean) ** 2; - } else { - $returnValue += ($arg - $aMean) ** 2; - } - ++$aCount; - } - } - } - - if (($aCount > 0) && ($returnValue >= 0)) { - return sqrt($returnValue / $aCount); - } - } - - return Functions::DIV0(); + return StandardDeviations::STDEVPA(...$args); } /** @@ -3472,14 +3180,14 @@ class Statistical $mArgs[] = $arg; } } - $discard = floor(self::COUNT($mArgs) * $percent / 2); + $discard = floor(Counts::COUNT($mArgs) * $percent / 2); sort($mArgs); for ($i = 0; $i < $discard; ++$i) { array_pop($mArgs); array_shift($mArgs); } - return self::AVERAGE($mArgs); + return Averages::AVERAGE($mArgs); } return Functions::VALUE(); @@ -3493,38 +3201,18 @@ class Statistical * Excel Function: * VAR(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * * @param mixed ...$args Data values * * @return float|string (string if result is an error) + * + *@see Statistical\Variances::VAR() + * Use the VAR() method in the Statistical\Variances class instead */ public static function VARFunc(...$args) { - $returnValue = Functions::DIV0(); - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - $aCount = 0; - foreach ($aArgs as $arg) { - if (is_bool($arg)) { - $arg = (int) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - - if ($aCount > 1) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1)); - } - - return $returnValue; + return Variances::VAR(...$args); } /** @@ -3535,51 +3223,18 @@ class Statistical * Excel Function: * VARA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Variances::VARA() + * Use the VARA() method in the Statistical\Variances class instead + * * @param mixed ...$args Data values * * @return float|string (string if result is an error) */ public static function VARA(...$args) { - $returnValue = Functions::DIV0(); - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = Functions::flattenArrayIndexed($args); - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ( - (is_string($arg)) && - (Functions::isValue($k)) - ) { - return Functions::VALUE(); - } elseif ( - (is_string($arg)) && - (!Functions::isMatrixValue($k)) - ) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - } - - if ($aCount > 1) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * ($aCount - 1)); - } - - return $returnValue; + return Variances::VARA(...$args); } /** @@ -3590,39 +3245,18 @@ class Statistical * Excel Function: * VARP(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Variances::VARP() + * Use the VARP() method in the Statistical\Variances class instead + * * @param mixed ...$args Data values * * @return float|string (string if result is an error) */ public static function VARP(...$args) { - // Return value - $returnValue = Functions::DIV0(); - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - $aCount = 0; - foreach ($aArgs as $arg) { - if (is_bool($arg)) { - $arg = (int) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - - if ($aCount > 0) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * $aCount); - } - - return $returnValue; + return Variances::VARP(...$args); } /** @@ -3633,51 +3267,18 @@ class Statistical * Excel Function: * VARPA(value1[,value2[, ...]]) * + * @Deprecated 1.17.0 + * + * @see Statistical\Variances::VARPA() + * Use the VARPA() method in the Statistical\Variances class instead + * * @param mixed ...$args Data values * * @return float|string (string if result is an error) */ public static function VARPA(...$args) { - $returnValue = Functions::DIV0(); - - $summerA = $summerB = 0; - - // Loop through arguments - $aArgs = Functions::flattenArrayIndexed($args); - $aCount = 0; - foreach ($aArgs as $k => $arg) { - if ( - (is_string($arg)) && - (Functions::isValue($k)) - ) { - return Functions::VALUE(); - } elseif ( - (is_string($arg)) && - (!Functions::isMatrixValue($k)) - ) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { - if (is_bool($arg)) { - $arg = (int) $arg; - } elseif (is_string($arg)) { - $arg = 0; - } - $summerA += ($arg * $arg); - $summerB += $arg; - ++$aCount; - } - } - } - - if ($aCount > 0) { - $summerA *= $aCount; - $summerB *= $summerB; - $returnValue = ($summerA - $summerB) / ($aCount * $aCount); - } - - return $returnValue; + return Variances::VARPA(...$args); } /** @@ -3734,10 +3335,10 @@ class Statistical $sigma = Functions::flattenSingleValue($sigma); if ($sigma === null) { - $sigma = self::STDEV($dataSet); + $sigma = StandardDeviations::STDEV($dataSet); } $n = count($dataSet); - return 1 - self::NORMSDIST((self::AVERAGE($dataSet) - $m0) / ($sigma / sqrt($n))); + return 1 - self::NORMSDIST((Averages::AVERAGE($dataSet) - $m0) / ($sigma / sqrt($n))); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/AggregateBase.php b/src/PhpSpreadsheet/Calculation/Statistical/AggregateBase.php new file mode 100644 index 00000000..75c012dc --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/AggregateBase.php @@ -0,0 +1,50 @@ + $arg) { + $arg = self::testAcceptedBoolean($arg, $k); + // Is it a numeric value? + // Strings containing numeric values are only counted if they are string literals (not cell values) + // and then only in MS Excel and in Open Office, not in Gnumeric + if ((is_string($arg)) && (!is_numeric($arg)) && (!Functions::isCellValue($k))) { + return Functions::VALUE(); + } + if (self::isAcceptedCountable($arg, $k)) { + $returnValue += abs($arg - $aMean); + ++$aCount; + } + } + + // Return + if ($aCount === 0) { + return Functions::DIV0(); + } + + return $returnValue / $aCount; + } + + /** + * AVERAGE. + * + * Returns the average (arithmetic mean) of the arguments + * + * Excel Function: + * AVERAGE(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string (string if result is an error) + */ + public static function AVERAGE(...$args) + { + $returnValue = $aCount = 0; + + // Loop through arguments + foreach (Functions::flattenArrayIndexed($args) as $k => $arg) { + $arg = self::testAcceptedBoolean($arg, $k); + // Is it a numeric value? + // Strings containing numeric values are only counted if they are string literals (not cell values) + // and then only in MS Excel and in Open Office, not in Gnumeric + if ((is_string($arg)) && (!is_numeric($arg)) && (!Functions::isCellValue($k))) { + return Functions::VALUE(); + } + if (self::isAcceptedCountable($arg, $k)) { + $returnValue += $arg; + ++$aCount; + } + } + + // Return + if ($aCount > 0) { + return $returnValue / $aCount; + } + + return Functions::DIV0(); + } + + /** + * AVERAGEA. + * + * Returns the average of its arguments, including numbers, text, and logical values + * + * Excel Function: + * AVERAGEA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string (string if result is an error) + */ + public static function AVERAGEA(...$args) + { + $returnValue = null; + + $aCount = 0; + // Loop through arguments + foreach (Functions::flattenArrayIndexed($args) as $k => $arg) { + if ((is_bool($arg)) && (!Functions::isMatrixValue($k))) { + } else { + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + if (is_bool($arg)) { + $arg = (int) $arg; + } elseif (is_string($arg)) { + $arg = 0; + } + $returnValue += $arg; + ++$aCount; + } + } + } + + if ($aCount > 0) { + return $returnValue / $aCount; + } + + return Functions::DIV0(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Counts.php b/src/PhpSpreadsheet/Calculation/Statistical/Counts.php new file mode 100644 index 00000000..13e7af79 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Counts.php @@ -0,0 +1,95 @@ + $arg) { + $arg = self::testAcceptedBoolean($arg, $k); + // Is it a numeric value? + // Strings containing numeric values are only counted if they are string literals (not cell values) + // and then only in MS Excel and in Open Office, not in Gnumeric + if (self::isAcceptedCountable($arg, $k)) { + ++$returnValue; + } + } + + return $returnValue; + } + + /** + * COUNTA. + * + * Counts the number of cells that are not empty within the list of arguments + * + * Excel Function: + * COUNTA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return int + */ + public static function COUNTA(...$args) + { + $returnValue = 0; + + // Loop through arguments + $aArgs = Functions::flattenArrayIndexed($args); + foreach ($aArgs as $k => $arg) { + // Nulls are counted if literals, but not if cell values + if ($arg !== null || (!Functions::isCellValue($k))) { + ++$returnValue; + } + } + + return $returnValue; + } + + /** + * COUNTBLANK. + * + * Counts the number of empty cells within the list of arguments + * + * Excel Function: + * COUNTBLANK(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return int + */ + public static function COUNTBLANK(...$args) + { + $returnValue = 0; + + // Loop through arguments + $aArgs = Functions::flattenArray($args); + foreach ($aArgs as $arg) { + // Is it a blank cell? + if (($arg === null) || ((is_string($arg)) && ($arg == ''))) { + ++$returnValue; + } + } + + return $returnValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php b/src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php new file mode 100644 index 00000000..bd17b062 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php @@ -0,0 +1,17 @@ + $returnValue)) { + $returnValue = $arg; + } + } + } + + if ($returnValue === null) { + return 0; + } + + return $returnValue; + } + + /** + * MAXA. + * + * Returns the greatest value in a list of arguments, including numbers, text, and logical values + * + * Excel Function: + * MAXA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float + */ + public static function MAXA(...$args) + { + $returnValue = null; + + // Loop through arguments + $aArgs = Functions::flattenArray($args); + foreach ($aArgs as $arg) { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + $arg = self::datatypeAdjustmentAllowStrings($arg); + if (($returnValue === null) || ($arg > $returnValue)) { + $returnValue = $arg; + } + } + } + + if ($returnValue === null) { + return 0; + } + + return $returnValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Minimum.php b/src/PhpSpreadsheet/Calculation/Statistical/Minimum.php new file mode 100644 index 00000000..bd46882e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Minimum.php @@ -0,0 +1,78 @@ + $arg) { + if ( + (is_bool($arg)) && + ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) + ) { + $arg = (int) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $returnValue += ($arg - $aMean) ** 2; + ++$aCount; + } + } + + if ($aCount > 0) { + return sqrt($returnValue / $aCount); + } + } + + return Functions::DIV0(); + } + + /** + * STDEVA. + * + * Estimates standard deviation based on a sample, including numbers, text, and logical values + * + * Excel Function: + * STDEVA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string + */ + public static function STDEVA(...$args) + { + $aArgs = Functions::flattenArrayIndexed($args); + + $aMean = Averages::AVERAGEA($aArgs); + + if (!is_string($aMean)) { + $returnValue = 0.0; + $aCount = -1; + + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && (!Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + $arg = self::datatypeAdjustmentAllowStrings($arg); + $returnValue += ($arg - $aMean) ** 2; + ++$aCount; + } + } + } + + if ($aCount > 0) { + return sqrt($returnValue / $aCount); + } + } + + return Functions::DIV0(); + } + + /** + * STDEVP. + * + * Calculates standard deviation based on the entire population + * + * Excel Function: + * STDEVP(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string + */ + public static function STDEVP(...$args) + { + $aArgs = Functions::flattenArrayIndexed($args); + + $aMean = Averages::AVERAGE($aArgs); + + if (!is_string($aMean)) { + $returnValue = 0.0; + $aCount = 0; + + foreach ($aArgs as $k => $arg) { + if ( + (is_bool($arg)) && + ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) + ) { + $arg = (int) $arg; + } + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $returnValue += ($arg - $aMean) ** 2; + ++$aCount; + } + } + + if ($aCount > 0) { + return sqrt($returnValue / $aCount); + } + } + + return Functions::DIV0(); + } + + /** + * STDEVPA. + * + * Calculates standard deviation based on the entire population, including numbers, text, and logical values + * + * Excel Function: + * STDEVPA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string + */ + public static function STDEVPA(...$args) + { + $aArgs = Functions::flattenArrayIndexed($args); + + $aMean = Averages::AVERAGEA($aArgs); + + if (!is_string($aMean)) { + $returnValue = 0.0; + $aCount = 0; + + foreach ($aArgs as $k => $arg) { + if ((is_bool($arg)) && (!Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + $arg = self::datatypeAdjustmentAllowStrings($arg); + $returnValue += ($arg - $aMean) ** 2; + ++$aCount; + } + } + } + + if ($aCount > 0) { + return sqrt($returnValue / $aCount); + } + } + + return Functions::DIV0(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php b/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php new file mode 100644 index 00000000..9762ec84 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php @@ -0,0 +1,26 @@ + 1) { + $summerA *= $aCount; + $summerB *= $summerB; + + return ($summerA - $summerB) / ($aCount * ($aCount - 1)); + } + + return $returnValue; + } + + /** + * VARA. + * + * Estimates variance based on a sample, including numbers, text, and logical values + * + * Excel Function: + * VARA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string (string if result is an error) + */ + public static function VARA(...$args) + { + $returnValue = Functions::DIV0(); + + $summerA = $summerB = 0.0; + + // Loop through arguments + $aArgs = Functions::flattenArrayIndexed($args); + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_string($arg)) && (Functions::isValue($k))) { + return Functions::VALUE(); + } elseif ((is_string($arg)) && (!Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { + $arg = self::datatypeAdjustmentAllowStrings($arg); + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + } + + if ($aCount > 1) { + $summerA *= $aCount; + $summerB *= $summerB; + + return ($summerA - $summerB) / ($aCount * ($aCount - 1)); + } + + return $returnValue; + } + + /** + * VARP. + * + * Calculates variance based on the entire population + * + * Excel Function: + * VARP(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string (string if result is an error) + */ + public static function VARP(...$args) + { + // Return value + $returnValue = Functions::DIV0(); + + $summerA = $summerB = 0.0; + + // Loop through arguments + $aArgs = Functions::flattenArray($args); + $aCount = 0; + foreach ($aArgs as $arg) { + $arg = self::datatypeAdjustmentBooleans($arg); + // Is it a numeric value? + if ((is_numeric($arg)) && (!is_string($arg))) { + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + + if ($aCount > 0) { + $summerA *= $aCount; + $summerB *= $summerB; + + return ($summerA - $summerB) / ($aCount * $aCount); + } + + return $returnValue; + } + + /** + * VARPA. + * + * Calculates variance based on the entire population, including numbers, text, and logical values + * + * Excel Function: + * VARPA(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string (string if result is an error) + */ + public static function VARPA(...$args) + { + $returnValue = Functions::DIV0(); + + $summerA = $summerB = 0.0; + + // Loop through arguments + $aArgs = Functions::flattenArrayIndexed($args); + $aCount = 0; + foreach ($aArgs as $k => $arg) { + if ((is_string($arg)) && (Functions::isValue($k))) { + return Functions::VALUE(); + } elseif ((is_string($arg)) && (!Functions::isMatrixValue($k))) { + } else { + // Is it a numeric value? + if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) & ($arg != '')))) { + $arg = self::datatypeAdjustmentAllowStrings($arg); + $summerA += ($arg * $arg); + $summerB += $arg; + ++$aCount; + } + } + } + + if ($aCount > 0) { + $summerA *= $aCount; + $summerB *= $summerB; + + return ($summerA - $summerB) / ($aCount * $aCount); + } + + return $returnValue; + } +} diff --git a/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php b/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php index 7530b1ef..56e917e3 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php @@ -24,7 +24,7 @@ class Tcpdf extends Pdf * * @param string $orientation Page orientation * @param string $unit Unit measure - * @param string $paperSize Paper size + * @param array|string $paperSize Paper size * * @return \TCPDF implementation */ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php new file mode 100644 index 00000000..9115db46 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php @@ -0,0 +1,26 @@ + Date: Tue, 2 Mar 2021 18:01:39 +0100 Subject: [PATCH 086/187] Statistics more unit tests (#1889) * Additional unit tests --- .../Calculation/Statistical.php | 14 +++++--- .../Functions/LookupRef/ColumnTest.php | 31 +++++++++++++++++ .../Functions/LookupRef/RowTest.php | 31 +++++++++++++++++ .../Functions/Statistical/SkewTest.php | 31 +++++++++++++++++ .../Functions/Statistical/TrimMeanTest.php | 32 +++++++++++++++++ tests/data/Calculation/LookupRef/COLUMN.php | 12 +++++++ tests/data/Calculation/LookupRef/ROW.php | 12 +++++++ tests/data/Calculation/Statistical/COVAR.php | 10 ++++++ .../data/Calculation/Statistical/FORECAST.php | 18 ++++++++++ .../Calculation/Statistical/INTERCEPT.php | 10 ++++++ tests/data/Calculation/Statistical/RSQ.php | 10 ++++++ tests/data/Calculation/Statistical/SKEW.php | 20 +++++++++++ tests/data/Calculation/Statistical/SLOPE.php | 10 ++++++ .../data/Calculation/Statistical/TRIMMEAN.php | 34 +++++++++++++++++++ 14 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php create mode 100644 tests/data/Calculation/LookupRef/COLUMN.php create mode 100644 tests/data/Calculation/LookupRef/ROW.php create mode 100644 tests/data/Calculation/Statistical/SKEW.php create mode 100644 tests/data/Calculation/Statistical/TRIMMEAN.php diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index dc9c5b44..0e15ecf4 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2753,13 +2753,16 @@ class Statistical $mean = Averages::AVERAGE($aArgs); $stdDev = StandardDeviations::STDEV($aArgs); + if ($stdDev === 0.0 || is_string($stdDev)) { + return Functions::DIV0(); + } + $count = $summer = 0; // Loop through arguments foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - (!Functions::isMatrixValue($k)) - ) { + if ((is_bool($arg)) && (!Functions::isMatrixValue($k))) { + } elseif (!is_numeric($arg)) { + return Functions::VALUE(); } else { // Is it a numeric value? if ((is_numeric($arg)) && (!is_string($arg))) { @@ -3173,6 +3176,7 @@ class Statistical if (($percent < 0) || ($percent > 1)) { return Functions::NAN(); } + $mArgs = []; foreach ($aArgs as $arg) { // Is it a numeric value? @@ -3180,8 +3184,10 @@ class Statistical $mArgs[] = $arg; } } + $discard = floor(Counts::COUNT($mArgs) * $percent / 2); sort($mArgs); + for ($i = 0; $i < $discard; ++$i) { array_pop($mArgs); array_shift($mArgs); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php new file mode 100644 index 00000000..203ee479 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php @@ -0,0 +1,31 @@ + Date: Tue, 2 Mar 2021 18:51:13 +0100 Subject: [PATCH 087/187] Changelog --- CHANGELOG.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ab843c2..8541d100 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,28 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.17.0 - 2021-03-01 + +### Added + - Implementation of the Excel `AVERAGEIFS()` functions as part of a restructuring of Database functions and Conditional Statistical functions. - Support for date values and percentages in query parameters for Database functions, and the IF expressions in functions like COUNTIF() and AVERAGEIF(). [#1875](https://github.com/PHPOffice/PhpSpreadsheet/pull/1875) - Support for booleans, and for wildcard text search in query parameters for Database functions, and the IF expressions in functions like COUNTIF() and AVERAGEIF(). [#1876](https://github.com/PHPOffice/PhpSpreadsheet/pull/1876) @@ -46,6 +68,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Nothing. ### Fixed + - Avoid Duplicate Titles When Reading Multiple HTML Files.[Issue #1823](https://github.com/PHPOffice/PhpSpreadsheet/issues/1823) [PR #1829](https://github.com/PHPOffice/PhpSpreadsheet/pull/1829) - Fixed issue with Worksheet's `getCell()` method when trying to get a cell by defined name. [#1858](https://github.com/PHPOffice/PhpSpreadsheet/issues/1858) - Fix possible endless loop in NumberFormat Masks [#1792](https://github.com/PHPOffice/PhpSpreadsheet/issues/1792) From c55269cb06911575a126dc225a05c0e4626e5fb4 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Tue, 2 Mar 2021 18:54:11 +0100 Subject: [PATCH 088/187] Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8541d100..419869bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Nothing. -## 1.17.0 - 2021-03-01 +## 1.17.1 - 2021-03-01 ### Added From 04e7c3075803f6d6e6bbf1ce560badae356e6225 Mon Sep 17 00:00:00 2001 From: oleibman Date: Wed, 3 Mar 2021 01:52:11 -0800 Subject: [PATCH 089/187] Fix Two 32-bit Timestamp Problems, and Minor getFormattedValue Bug (#1891) I ran the test suite using 32-bit PHP. There were 2 places where changes were needed due to 32-bit timestamps. Reader\\Xml.php was using strtotime as an intermediate step in converting a string timestamp to an Excel timestamp. The XML file type stores pure timestamps (i.e. no date portion) as, e.g., 1899-12-31T02:30:00.000, and that value causes an error using strtotime on a 32-bit system. However, it is sufficient to use that value in a DateTime constructor, and that will work for 32- and 64-bit. There was no test for that particular cell, so I added one to the XML read test. And that's when I discovered the getFormattedValue bug. The cell's format is `hh":"mm":"ss`. The quotes around the colons are disrupting the formatting. PhpSpreadsheet formats the cell by converting the Excel format to a Php Date format, in this case `H\:m\:s`. That's a problem, since Excel thinks 'm' means *minutes*, but PHP thinks it means *months*. This is not a problem when the colon is not quoted; there are ample tests for that. I added my best guess as to how to recognize this situation, changing `\:m` to `:i`. The XML read test now succeeds, and no other tests were broken by this change. Test Shared\\DateTest had one test where the expected result of converting to a Unix timestamp exceeds 2**32. Since a Unix timestamp is strictly an int, that test fails on a 32-bit system. In the discussion regarding recently merged PR #1870, it was felt that the user base might still be using the functions that convert to and from a timestamp. So, we should not drop this test, but, since it cannot succeed on a 32-bit system, I changed it to be skipped whenever the expected result exceeded PHP_INT_MAX. There are 3 "toTimestamp" functions within that test. Only one of these had been affected, but I thought it was a good idea to add additional tests to the others to demonstrate this condition. In the course of testing, I also discovered some 32-bit problems with bitwise and base-conversion functions. I am preparing separate PRs to deal with those. --- src/PhpSpreadsheet/Reader/Xml.php | 5 ++++- src/PhpSpreadsheet/Style/NumberFormat.php | 4 ++++ .../PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php | 4 ++++ tests/PhpSpreadsheetTests/Shared/DateTest.php | 13 +++++++++++++ tests/data/Shared/Date/ExcelToTimestamp1900.php | 7 +++++++ tests/data/Shared/Date/ExcelToTimestamp1904.php | 5 +++++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index f38a9515..b1df0ef5 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Reader; +use DateTime; +use DateTimeZone; use PhpOffice\PhpSpreadsheet\Cell\AddressHelper; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; @@ -557,7 +559,8 @@ class Xml extends BaseReader break; case 'DateTime': $type = DataType::TYPE_NUMERIC; - $cellValue = Date::PHPToExcel(strtotime($cellValue . ' UTC')); + $dateTime = new DateTime($cellValue, new DateTimeZone('UTC')); + $cellValue = Date::PHPToExcel($dateTime); break; case 'Error': diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index a96d2ac3..a623657b 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -502,6 +502,10 @@ class NumberFormat extends Supervisor $format = preg_replace_callback('/"(.*)"/U', ['self', 'escapeQuotesCallback'], $format); $dateObj = Date::excelToDateTimeObject($value); + // If the colon preceding minute had been quoted, as happens in + // Excel 2003 XML formats, m will not have been changed to i above. + // Change it now. + $format = \preg_replace('/\\\\:m/', ':i', $format); $value = $dateObj->format($format); } diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php index 969571f2..3783c1a9 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php @@ -36,6 +36,10 @@ class XmlLoadTest extends TestCase self::assertEquals('# ?0/??0', $sheet->getCell('A11')->getStyle()->getNumberFormat()->getFormatCode()); // Same pattern, same value, different display in Gnumeric vs Excel //self::assertEquals('1 1/2', $sheet->getCell('A11')->getFormattedValue()); + self::assertEquals('hh":"mm":"ss', $sheet->getCell('A13')->getStyle()->getNumberFormat()->getFormatCode()); + self::assertEquals('02:30:00', $sheet->getCell('A13')->getFormattedValue()); + self::assertEquals('d/m/yy hh":"mm', $sheet->getCell('A15')->getStyle()->getNumberFormat()->getFormatCode()); + self::assertEquals('19/12/60 01:30', $sheet->getCell('A15')->getFormattedValue()); self::assertEquals('=B1+C1', $sheet->getCell('H1')->getValue()); self::assertEquals('=E2&F2', $sheet->getCell('J2')->getValue()); diff --git a/tests/PhpSpreadsheetTests/Shared/DateTest.php b/tests/PhpSpreadsheetTests/Shared/DateTest.php index 7254635e..550e2f6a 100644 --- a/tests/PhpSpreadsheetTests/Shared/DateTest.php +++ b/tests/PhpSpreadsheetTests/Shared/DateTest.php @@ -8,16 +8,20 @@ use PHPUnit\Framework\TestCase; class DateTest extends TestCase { + private $excelCalendar; + private $dttimezone; protected function setUp(): void { $this->dttimezone = Date::getDefaultTimeZone(); + $this->excelCalendar = Date::getExcelCalendar(); } protected function tearDown(): void { Date::setDefaultTimeZone($this->dttimezone); + Date::setExcelCalendar($this->excelCalendar); } public function testSetExcelCalendar(): void @@ -47,6 +51,9 @@ class DateTest extends TestCase */ public function testDateTimeExcelToTimestamp1900($expectedResult, ...$args): void { + if (is_numeric($expectedResult) && ($expectedResult > PHP_INT_MAX || $expectedResult < PHP_INT_MIN)) { + self::markTestSkipped('Test invalid on 32-bit system.'); + } Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); $result = Date::excelToTimestamp(...$args); @@ -119,6 +126,9 @@ class DateTest extends TestCase */ public function testDateTimeExcelToTimestamp1904($expectedResult, ...$args): void { + if (is_numeric($expectedResult) && ($expectedResult > PHP_INT_MAX || $expectedResult < PHP_INT_MIN)) { + self::markTestSkipped('Test invalid on 32-bit system.'); + } Date::setExcelCalendar(Date::CALENDAR_MAC_1904); $result = Date::excelToTimestamp(...$args); @@ -171,6 +181,9 @@ class DateTest extends TestCase */ public function testDateTimeExcelToTimestamp1900Timezone($expectedResult, ...$args): void { + if (is_numeric($expectedResult) && ($expectedResult > PHP_INT_MAX || $expectedResult < PHP_INT_MIN)) { + self::markTestSkipped('Test invalid on 32-bit system.'); + } Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); $result = Date::excelToTimestamp(...$args); diff --git a/tests/data/Shared/Date/ExcelToTimestamp1900.php b/tests/data/Shared/Date/ExcelToTimestamp1900.php index ab79731e..ffcd194f 100644 --- a/tests/data/Shared/Date/ExcelToTimestamp1900.php +++ b/tests/data/Shared/Date/ExcelToTimestamp1900.php @@ -72,4 +72,11 @@ return [ 10666, 0.12345, ], + // 29-Apr-2038 00:00:00 beyond PHP 32-bit Latest Date + [ + 2156112000, + 50524, + ], + [-2147483648, -2147483648 / 86400], // Okay on 64- and 32-bit systems + [-2147483649, -2147483649 / 86400], // Skipped test on 32-bit ]; diff --git a/tests/data/Shared/Date/ExcelToTimestamp1904.php b/tests/data/Shared/Date/ExcelToTimestamp1904.php index 1c013ab4..fc55238a 100644 --- a/tests/data/Shared/Date/ExcelToTimestamp1904.php +++ b/tests/data/Shared/Date/ExcelToTimestamp1904.php @@ -42,4 +42,9 @@ return [ gmmktime(13, 02, 13, 1, 1, 1904), // 32-bit safe - no Y2038 problem 0.54321, ], + // 29-Apr-2038 00:00:00 beyond PHP 32-bit Latest Date + [ + 2156112000, + 49062, + ], ]; From 70e371189c9030b96bad9723ba38d46268365292 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 3 Mar 2021 12:51:50 +0100 Subject: [PATCH 090/187] Move the trend functions from Statistical and into their own group class (#1890) * Move the trend functions from Statistical and into their own group class * Additional LINEST()/LOGEST() tests, and fix for the returned array --- .../Calculation/Calculation.php | 22 +- .../Calculation/Statistical.php | 283 +++----------- .../Calculation/Statistical/Trends.php | 359 ++++++++++++++++++ tests/data/Calculation/Statistical/LINEST.php | 38 ++ tests/data/Calculation/Statistical/LOGEST.php | 7 + 5 files changed, 470 insertions(+), 239 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Trends.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index bc0baa4d..7fd07355 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -599,7 +599,7 @@ class Calculation ], 'CORREL' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CORREL'], + 'functionCall' => [Statistical\Trends::class, 'CORREL'], 'argumentCount' => '2', ], 'COS' => [ @@ -679,12 +679,12 @@ class Calculation ], 'COVAR' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COVAR'], + 'functionCall' => [Statistical\Trends::class, 'COVAR'], 'argumentCount' => '2', ], 'COVARIANCE.P' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'COVAR'], + 'functionCall' => [Statistical\Trends::class, 'COVAR'], 'argumentCount' => '2', ], 'COVARIANCE.S' => [ @@ -1084,7 +1084,7 @@ class Calculation ], 'FORECAST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'FORECAST'], + 'functionCall' => [Statistical\Trends::class, 'FORECAST'], 'argumentCount' => '3', ], 'FORECAST.ETS' => [ @@ -1109,7 +1109,7 @@ class Calculation ], 'FORECAST.LINEAR' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'FORECAST'], + 'functionCall' => [Statistical\Trends::class, 'FORECAST'], 'argumentCount' => '3', ], 'FORMULATEXT' => [ @@ -1423,7 +1423,7 @@ class Calculation ], 'INTERCEPT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'INTERCEPT'], + 'functionCall' => [Statistical\Trends::class, 'INTERCEPT'], 'argumentCount' => '2', ], 'INTRATE' => [ @@ -1560,7 +1560,7 @@ class Calculation ], 'LINEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'LINEST'], + 'functionCall' => [Statistical\Trends::class, 'LINEST'], 'argumentCount' => '1-4', ], 'LN' => [ @@ -1580,7 +1580,7 @@ class Calculation ], 'LOGEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'LOGEST'], + 'functionCall' => [Statistical\Trends::class, 'LOGEST'], 'argumentCount' => '1-4', ], 'LOGINV' => [ @@ -2143,7 +2143,7 @@ class Calculation ], 'RSQ' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'RSQ'], + 'functionCall' => [Statistical\Trends::class, 'RSQ'], 'argumentCount' => '2', ], 'RTD' => [ @@ -2228,7 +2228,7 @@ class Calculation ], 'SLOPE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'SLOPE'], + 'functionCall' => [Statistical\Trends::class, 'SLOPE'], 'argumentCount' => '2', ], 'SMALL' => [ @@ -2293,7 +2293,7 @@ class Calculation ], 'STEYX' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'STEYX'], + 'functionCall' => [Statistical\Trends::class, 'STEYX'], 'argumentCount' => '2', ], 'SUBSTITUTE' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 0e15ecf4..b2b9ad50 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -9,6 +9,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Maximum; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Minimum; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Permutations; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\StandardDeviations; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Trends; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances; use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend; @@ -21,33 +22,6 @@ class Statistical const MAX_ITERATIONS = 256; const SQRT2PI = 2.5066282746310005024157652848110452530069867406099; - private static function checkTrendArrays(&$array1, &$array2) - { - if (!is_array($array1)) { - $array1 = [$array1]; - } - if (!is_array($array2)) { - $array2 = [$array2]; - } - - $array1 = Functions::flattenArray($array1); - $array2 = Functions::flattenArray($array2); - foreach ($array1 as $key => $value) { - if ((is_bool($value)) || (is_string($value)) || ($value === null)) { - unset($array1[$key], $array2[$key]); - } - } - foreach ($array2 as $key => $value) { - if ((is_bool($value)) || (is_string($value)) || ($value === null)) { - unset($array1[$key], $array2[$key]); - } - } - $array1 = array_merge($array1); - $array2 = array_merge($array2); - - return true; - } - /** * Incomplete beta function. * @@ -890,6 +864,11 @@ class Statistical * * Returns covariance, the average of the products of deviations for each data point pair. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::CORREL() + * Use the CORREL() method in the Statistical\Trends class instead + * * @param mixed $yValues array of mixed Data Series Y * @param null|mixed $xValues array of mixed Data Series X * @@ -897,24 +876,7 @@ class Statistical */ public static function CORREL($yValues, $xValues = null) { - if (($xValues === null) || (!is_array($yValues)) || (!is_array($xValues))) { - return Functions::VALUE(); - } - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getCorrelation(); + return Trends::CORREL($xValues, $yValues); } /** @@ -1033,6 +995,11 @@ class Statistical * * Returns covariance, the average of the products of deviations for each data point pair. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::COVAR() + * Use the COVAR() method in the Statistical\Trends class instead + * * @param mixed $yValues array of mixed Data Series Y * @param mixed $xValues array of mixed Data Series X * @@ -1040,21 +1007,7 @@ class Statistical */ public static function COVAR($yValues, $xValues) { - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getCovariance(); + return Trends::COVAR($yValues, $xValues); } /** @@ -1380,6 +1333,11 @@ class Statistical * * Calculates, or predicts, a future value by using existing values. The predicted value is a y-value for a given x-value. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::FORECAST() + * Use the FORECAST() method in the Statistical\Trends class instead + * * @param float $xValue Value of X for which we want to find Y * @param mixed $yValues array of mixed Data Series Y * @param mixed $xValues of mixed Data Series X @@ -1388,24 +1346,7 @@ class Statistical */ public static function FORECAST($xValue, $yValues, $xValues) { - $xValue = Functions::flattenSingleValue($xValue); - if (!is_numeric($xValue)) { - return Functions::VALUE(); - } elseif (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getValueOfYForX($xValue); + return Trends::FORECAST($xValue, $yValues, $xValues); } /** @@ -1722,6 +1663,11 @@ class Statistical * * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::INTERCEPT() + * Use the INTERCEPT() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @@ -1729,21 +1675,7 @@ class Statistical */ public static function INTERCEPT($yValues, $xValues) { - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getIntersect(); + return Trends::INTERCEPT($yValues, $xValues); } /** @@ -1838,6 +1770,11 @@ class Statistical * Calculates the statistics for a line by using the "least squares" method to calculate a straight line that best fits your data, * and then returns an array that describes the line. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::LINEST() + * Use the LINEST() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param null|mixed[] $xValues Data Series X * @param bool $const a logical value specifying whether to force the intersect to equal 0 @@ -1847,48 +1784,7 @@ class Statistical */ public static function LINEST($yValues, $xValues = null, $const = true, $stats = false) { - $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); - $stats = ($stats === null) ? false : (bool) Functions::flattenSingleValue($stats); - if ($xValues === null) { - $xValues = range(1, count(Functions::flattenArray($yValues))); - } - - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return 0; - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues, $const); - if ($stats) { - return [ - [ - $bestFitLinear->getSlope(), - $bestFitLinear->getSlopeSE(), - $bestFitLinear->getGoodnessOfFit(), - $bestFitLinear->getF(), - $bestFitLinear->getSSRegression(), - ], - [ - $bestFitLinear->getIntersect(), - $bestFitLinear->getIntersectSE(), - $bestFitLinear->getStdevOfResiduals(), - $bestFitLinear->getDFResiduals(), - $bestFitLinear->getSSResiduals(), - ], - ]; - } - - return [ - $bestFitLinear->getSlope(), - $bestFitLinear->getIntersect(), - ]; + return Trends::LINEST($yValues, $xValues, $const, $stats); } /** @@ -1897,6 +1793,11 @@ class Statistical * Calculates an exponential curve that best fits the X and Y data series, * and then returns an array that describes the line. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::LOGEST() + * Use the LOGEST() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param null|mixed[] $xValues Data Series X * @param bool $const a logical value specifying whether to force the intersect to equal 0 @@ -1906,54 +1807,7 @@ class Statistical */ public static function LOGEST($yValues, $xValues = null, $const = true, $stats = false) { - $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); - $stats = ($stats === null) ? false : (bool) Functions::flattenSingleValue($stats); - if ($xValues === null) { - $xValues = range(1, count(Functions::flattenArray($yValues))); - } - - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - foreach ($yValues as $value) { - if ($value <= 0.0) { - return Functions::NAN(); - } - } - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return 1; - } - - $bestFitExponential = Trend::calculate(Trend::TREND_EXPONENTIAL, $yValues, $xValues, $const); - if ($stats) { - return [ - [ - $bestFitExponential->getSlope(), - $bestFitExponential->getSlopeSE(), - $bestFitExponential->getGoodnessOfFit(), - $bestFitExponential->getF(), - $bestFitExponential->getSSRegression(), - ], - [ - $bestFitExponential->getIntersect(), - $bestFitExponential->getIntersectSE(), - $bestFitExponential->getStdevOfResiduals(), - $bestFitExponential->getDFResiduals(), - $bestFitExponential->getSSResiduals(), - ], - ]; - } - - return [ - $bestFitExponential->getSlope(), - $bestFitExponential->getIntersect(), - ]; + return Trends::LOGEST($yValues, $xValues, $const, $stats); } /** @@ -2711,6 +2565,11 @@ class Statistical * * Returns the square of the Pearson product moment correlation coefficient through data points in known_y's and known_x's. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::RSQ() + * Use the RSQ() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @@ -2718,21 +2577,7 @@ class Statistical */ public static function RSQ($yValues, $xValues) { - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getGoodnessOfFit(); + return Trends::RSQ($yValues, $xValues); } /** @@ -2784,6 +2629,11 @@ class Statistical * * Returns the slope of the linear regression line through data points in known_y's and known_x's. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::SLOPE() + * Use the SLOPE() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @@ -2791,21 +2641,7 @@ class Statistical */ public static function SLOPE($yValues, $xValues) { - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getSlope(); + return Trends::SLOPE($yValues, $xValues); } /** @@ -2971,6 +2807,11 @@ class Statistical /** * STEYX. * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::STEYX() + * Use the STEYX() method in the Statistical\Trends class instead + * * Returns the standard error of the predicted y-value for each x in the regression. * * @param mixed[] $yValues Data Series Y @@ -2980,21 +2821,7 @@ class Statistical */ public static function STEYX($yValues, $xValues) { - if (!self::checkTrendArrays($yValues, $xValues)) { - return Functions::VALUE(); - } - $yValueCount = count($yValues); - $xValueCount = count($xValues); - - if (($yValueCount == 0) || ($yValueCount != $xValueCount)) { - return Functions::NA(); - } elseif ($yValueCount == 1) { - return Functions::DIV0(); - } - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); - - return $bestFitLinear->getStdevOfResiduals(); + return Trends::STEYX($yValues, $xValues); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php new file mode 100644 index 00000000..032b4625 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -0,0 +1,359 @@ + $value) { + if ((is_bool($value)) || (is_string($value)) || ($value === null)) { + unset($array1[$key], $array2[$key]); + } + } + } + + private static function checkTrendArrays(&$array1, &$array2): void + { + if (!is_array($array1)) { + $array1 = [$array1]; + } + if (!is_array($array2)) { + $array2 = [$array2]; + } + + $array1 = Functions::flattenArray($array1); + $array2 = Functions::flattenArray($array2); + + self::filterTrendValues($array1, $array2); + self::filterTrendValues($array2, $array1); + + // Reset the array indexes + $array1 = array_merge($array1); + $array2 = array_merge($array2); + } + + protected static function validateTrendArrays(array $yValues, array $xValues): void + { + $yValueCount = count($yValues); + $xValueCount = count($xValues); + + if (($yValueCount === 0) || ($yValueCount !== $xValueCount)) { + throw new Exception(Functions::NA()); + } elseif ($yValueCount === 1) { + throw new Exception(Functions::DIV0()); + } + } + + /** + * CORREL. + * + * Returns covariance, the average of the products of deviations for each data point pair. + * + * @param mixed $yValues array of mixed Data Series Y + * @param null|mixed $xValues array of mixed Data Series X + * + * @return float|string + */ + public static function CORREL($yValues, $xValues = null) + { + if (($xValues === null) || (!is_array($yValues)) || (!is_array($xValues))) { + return Functions::VALUE(); + } + + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getCorrelation(); + } + + /** + * COVAR. + * + * Returns covariance, the average of the products of deviations for each data point pair. + * + * @param mixed $yValues array of mixed Data Series Y + * @param mixed $xValues array of mixed Data Series X + * + * @return float|string + */ + public static function COVAR($yValues, $xValues) + { + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getCovariance(); + } + + /** + * FORECAST. + * + * Calculates, or predicts, a future value by using existing values. + * The predicted value is a y-value for a given x-value. + * + * @param float $xValue Value of X for which we want to find Y + * @param mixed $yValues array of mixed Data Series Y + * @param mixed $xValues of mixed Data Series X + * + * @return bool|float|string + */ + public static function FORECAST($xValue, $yValues, $xValues) + { + $xValue = Functions::flattenSingleValue($xValue); + if (!is_numeric($xValue)) { + return Functions::VALUE(); + } + + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getValueOfYForX($xValue); + } + + /** + * INTERCEPT. + * + * Calculates the point at which a line will intersect the y-axis by using existing x-values and y-values. + * + * @param mixed[] $yValues Data Series Y + * @param mixed[] $xValues Data Series X + * + * @return float|string + */ + public static function INTERCEPT($yValues, $xValues) + { + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getIntersect(); + } + + /** + * LINEST. + * + * Calculates the statistics for a line by using the "least squares" method to calculate a straight line + * that best fits your data, and then returns an array that describes the line. + * + * @param mixed[] $yValues Data Series Y + * @param null|mixed[] $xValues Data Series X + * @param bool $const a logical value specifying whether to force the intersect to equal 0 + * @param bool $stats a logical value specifying whether to return additional regression statistics + * + * @return array|int|string The result, or a string containing an error + */ + public static function LINEST($yValues, $xValues = null, $const = true, $stats = false) + { + $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); + $stats = ($stats === null) ? false : (bool) Functions::flattenSingleValue($stats); + if ($xValues === null) { + $xValues = $yValues; + } + + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues, $const); + + if ($stats === true) { + return [ + [ + $bestFitLinear->getSlope(), + $bestFitLinear->getIntersect(), + ], + [ + $bestFitLinear->getSlopeSE(), + $bestFitLinear->getIntersectSE(), + ], + [ + $bestFitLinear->getGoodnessOfFit(), + $bestFitLinear->getStdevOfResiduals(), + ], + [ + $bestFitLinear->getF(), + $bestFitLinear->getDFResiduals(), + ], + [ + $bestFitLinear->getSSRegression(), + $bestFitLinear->getSSResiduals(), + ], + ]; + } + + return [ + $bestFitLinear->getSlope(), + $bestFitLinear->getIntersect(), + ]; + } + + /** + * LOGEST. + * + * Calculates an exponential curve that best fits the X and Y data series, + * and then returns an array that describes the line. + * + * @param mixed[] $yValues Data Series Y + * @param null|mixed[] $xValues Data Series X + * @param bool $const a logical value specifying whether to force the intersect to equal 0 + * @param bool $stats a logical value specifying whether to return additional regression statistics + * + * @return array|int|string The result, or a string containing an error + */ + public static function LOGEST($yValues, $xValues = null, $const = true, $stats = false) + { + $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); + $stats = ($stats === null) ? false : (bool) Functions::flattenSingleValue($stats); + if ($xValues === null) { + $xValues = $yValues; + } + + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + foreach ($yValues as $value) { + if ($value < 0.0) { + return Functions::NAN(); + } + } + + $bestFitExponential = Trend::calculate(Trend::TREND_EXPONENTIAL, $yValues, $xValues, $const); + + if ($stats === true) { + return [ + [ + $bestFitExponential->getSlope(), + $bestFitExponential->getIntersect(), + ], + [ + $bestFitExponential->getSlopeSE(), + $bestFitExponential->getIntersectSE(), + ], + [ + $bestFitExponential->getGoodnessOfFit(), + $bestFitExponential->getStdevOfResiduals(), + ], + [ + $bestFitExponential->getF(), + $bestFitExponential->getDFResiduals(), + ], + [ + $bestFitExponential->getSSRegression(), + $bestFitExponential->getSSResiduals(), + ], + ]; + } + + return [ + $bestFitExponential->getSlope(), + $bestFitExponential->getIntersect(), + ]; + } + + /** + * RSQ. + * + * Returns the square of the Pearson product moment correlation coefficient through data points + * in known_y's and known_x's. + * + * @param mixed[] $yValues Data Series Y + * @param mixed[] $xValues Data Series X + * + * @return float|string The result, or a string containing an error + */ + public static function RSQ($yValues, $xValues) + { + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getGoodnessOfFit(); + } + + /** + * SLOPE. + * + * Returns the slope of the linear regression line through data points in known_y's and known_x's. + * + * @param mixed[] $yValues Data Series Y + * @param mixed[] $xValues Data Series X + * + * @return float|string The result, or a string containing an error + */ + public static function SLOPE($yValues, $xValues) + { + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getSlope(); + } + + /** + * STEYX. + * + * Returns the standard error of the predicted y-value for each x in the regression. + * + * @param mixed[] $yValues Data Series Y + * @param mixed[] $xValues Data Series X + * + * @return float|string + */ + public static function STEYX($yValues, $xValues) + { + try { + self::checkTrendArrays($yValues, $xValues); + self::validateTrendArrays($yValues, $xValues); + } catch (Exception $e) { + return $e->getMessage(); + } + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues); + + return $bestFitLinear->getStdevOfResiduals(); + } +} diff --git a/tests/data/Calculation/Statistical/LINEST.php b/tests/data/Calculation/Statistical/LINEST.php index 2b2680c7..9bd28ffe 100644 --- a/tests/data/Calculation/Statistical/LINEST.php +++ b/tests/data/Calculation/Statistical/LINEST.php @@ -8,4 +8,42 @@ return [ true, false, ], + [ + [ + [56.837944664032, 11704.347826086974], + [54.403741747077, 131988.39973671117], + [0.108159322123, 13123.598915116556], + [1.091488562082, 9], + [187985818.1818185, 1550059636.363636], + ], + [142000, 144000, 151000, 150000, 139000, 169000, 126000, 142900, 163000, 169000, 149000], + [2310, 2333, 2356, 2379, 2402, 2425, 2448, 2471, 2494, 2517, 2540], + true, + true, + ], + // [ + // [ + // [-234.2371645, 2553.21066, 12529.76817, 27.64138737, 52317.83051], + // [13.26801148, 530.6691519, 400.0668382, 5.429374042, 12237.3616], + // [0.996747993, 970.5784629, '#N/A', '#N/A', '#N/A'], + // [459.7536742, 6, '#N/A', '#N/A', '#N/A'], + // [1732393319, 5652135.316, '#N/A', '#N/A', '#N/A'], + // ], + // [142000, 144000, 151000, 150000, 139000, 169000, 126000, 142900, 163000, 169000, 149000], + // [ + // [2310, 2, 2, 20], + // [2333, 2, 2, 12], + // [2356, 3, 1.5, 33], + // [2379, 3, 2, 43], + // [2402, 2, 3, 53], + // [2425, 4, 2, 23], + // [2448, 2, 1.5, 99], + // [2471, 2, 2, 34], + // [2494, 3, 3, 23], + // [2517, 4, 4, 55], + // [2540, 2, 3, 22], + // ], + // true, + // true, + // ], ]; diff --git a/tests/data/Calculation/Statistical/LOGEST.php b/tests/data/Calculation/Statistical/LOGEST.php index e74db005..be9e4d72 100644 --- a/tests/data/Calculation/Statistical/LOGEST.php +++ b/tests/data/Calculation/Statistical/LOGEST.php @@ -8,4 +8,11 @@ return [ true, false, ], + [ + [1.482939830687, 2.257475168225], + [2, 3, 6, 8, 12, 15, 25, 34, 50], + [0, 1, 2, 3, 4, 5, 6, 7, 8], + true, + false, + ], ]; From 3e672710cd1c9b96b7029763de5d94954b07f8af Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 3 Mar 2021 18:16:37 +0100 Subject: [PATCH 091/187] Writing defined names without a worksheet reference in Xlsx (#1892) --- src/PhpSpreadsheet/Writer/Xls/Workbook.php | 4 ++-- src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index 2b4895f0..831c120b 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -551,8 +551,8 @@ class Workbook extends BIFFwriter $newRange = ''; if (empty($worksheet)) { if (($offset === 0) || ($definedRange[$offset - 1] !== ':')) { - // We need a worksheet - $worksheet = $pDefinedName->getWorksheet()->getTitle(); + // We should have a worksheet + $worksheet = $pDefinedName->getWorksheet() ? $pDefinedName->getWorksheet()->getTitle() : null; } } else { $worksheet = str_replace("''", "'", trim($worksheet, "'")); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php b/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php index 8c3da827..a1ea02ba 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php @@ -99,7 +99,7 @@ class DefinedNames if (empty($worksheet)) { if (($offset === 0) || ($definedRange[$offset - 1] !== ':')) { // We should have a worksheet - $worksheet = $pDefinedName->getWorksheet()->getTitle(); + $worksheet = $pDefinedName->getWorksheet() ? $pDefinedName->getWorksheet()->getTitle() : null; } } else { $worksheet = str_replace("''", "'", trim($worksheet, "'")); From 60023e48f2ade64fe4a52036a09be5c700737d42 Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Wed, 3 Mar 2021 18:49:46 +0100 Subject: [PATCH 092/187] Refactoring --- .../Writer/Xlsx/DefinedNames.php | 107 ++++++++++-------- 1 file changed, 57 insertions(+), 50 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php b/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php index a1ea02ba..30aa45a3 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php @@ -72,55 +72,7 @@ class DefinedNames $this->objWriter->writeAttribute('localSheetId', $pDefinedName->getScope()->getParent()->getIndex($pDefinedName->getScope())); } - $definedRange = $pDefinedName->getValue(); - $splitCount = preg_match_all( - '/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/mui', - $definedRange, - $splitRanges, - PREG_OFFSET_CAPTURE - ); - - $lengths = array_map('strlen', array_column($splitRanges[0], 0)); - $offsets = array_column($splitRanges[0], 1); - - $worksheets = $splitRanges[2]; - $columns = $splitRanges[6]; - $rows = $splitRanges[7]; - - while ($splitCount > 0) { - --$splitCount; - $length = $lengths[$splitCount]; - $offset = $offsets[$splitCount]; - $worksheet = $worksheets[$splitCount][0]; - $column = $columns[$splitCount][0]; - $row = $rows[$splitCount][0]; - - $newRange = ''; - if (empty($worksheet)) { - if (($offset === 0) || ($definedRange[$offset - 1] !== ':')) { - // We should have a worksheet - $worksheet = $pDefinedName->getWorksheet() ? $pDefinedName->getWorksheet()->getTitle() : null; - } - } else { - $worksheet = str_replace("''", "'", trim($worksheet, "'")); - } - if (!empty($worksheet)) { - $newRange = "'" . str_replace("'", "''", $worksheet) . "'!"; - } - - if (!empty($column)) { - $newRange .= $column; - } - if (!empty($row)) { - $newRange .= $row; - } - - $definedRange = substr($definedRange, 0, $offset) . $newRange . substr($definedRange, $offset + $length); - } - - if (substr($definedRange, 0, 1) === '=') { - $definedRange = substr($definedRange, 1); - } + $definedRange = $this->getDefinedRange($pDefinedName); $this->objWriter->writeRawData($definedRange); @@ -144,7 +96,7 @@ class DefinedNames $range = Coordinate::splitRange($autoFilterRange); $range = $range[0]; // Strip any worksheet ref so we can make the cell ref absolute - [$ws, $range[0]] = Worksheet::extractSheetTitle($range[0], true); + [, $range[0]] = Worksheet::extractSheetTitle($range[0], true); $range[0] = Coordinate::absoluteCoordinate($range[0]); $range[1] = Coordinate::absoluteCoordinate($range[1]); @@ -220,4 +172,59 @@ class DefinedNames $this->objWriter->endElement(); } } + + private function getDefinedRange(DefinedName $pDefinedName): string + { + $definedRange = $pDefinedName->getValue(); + $splitCount = preg_match_all( + '/' . Calculation::CALCULATION_REGEXP_CELLREF_RELATIVE . '/mui', + $definedRange, + $splitRanges, + PREG_OFFSET_CAPTURE + ); + + $lengths = array_map('strlen', array_column($splitRanges[0], 0)); + $offsets = array_column($splitRanges[0], 1); + + $worksheets = $splitRanges[2]; + $columns = $splitRanges[6]; + $rows = $splitRanges[7]; + + while ($splitCount > 0) { + --$splitCount; + $length = $lengths[$splitCount]; + $offset = $offsets[$splitCount]; + $worksheet = $worksheets[$splitCount][0]; + $column = $columns[$splitCount][0]; + $row = $rows[$splitCount][0]; + + $newRange = ''; + if (empty($worksheet)) { + if (($offset === 0) || ($definedRange[$offset - 1] !== ':')) { + // We should have a worksheet + $worksheet = $pDefinedName->getWorksheet() ? $pDefinedName->getWorksheet()->getTitle() : null; + } + } else { + $worksheet = str_replace("''", "'", trim($worksheet, "'")); + } + if (!empty($worksheet)) { + $newRange = "'" . str_replace("'", "''", $worksheet) . "'!"; + } + + if (!empty($column)) { + $newRange .= $column; + } + if (!empty($row)) { + $newRange .= $row; + } + + $definedRange = substr($definedRange, 0, $offset) . $newRange . substr($definedRange, $offset + $length); + } + + if (substr($definedRange, 0, 1) === '=') { + $definedRange = substr($definedRange, 1); + } + + return $definedRange; + } } From 1272224164ad9f00bed818d2eb5df8224836160b Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Wed, 3 Mar 2021 19:12:06 +0100 Subject: [PATCH 093/187] Minor Refactoring --- src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php b/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php index 30aa45a3..4c0929db 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php @@ -69,7 +69,10 @@ class DefinedNames $this->objWriter->startElement('definedName'); $this->objWriter->writeAttribute('name', $pDefinedName->getName()); if ($pDefinedName->getLocalOnly() && $pDefinedName->getScope() !== null) { - $this->objWriter->writeAttribute('localSheetId', $pDefinedName->getScope()->getParent()->getIndex($pDefinedName->getScope())); + $this->objWriter->writeAttribute( + 'localSheetId', + $pDefinedName->getScope()->getParent()->getIndex($pDefinedName->getScope()) + ); } $definedRange = $this->getDefinedRange($pDefinedName); @@ -207,16 +210,11 @@ class DefinedNames } else { $worksheet = str_replace("''", "'", trim($worksheet, "'")); } + if (!empty($worksheet)) { $newRange = "'" . str_replace("'", "''", $worksheet) . "'!"; } - - if (!empty($column)) { - $newRange .= $column; - } - if (!empty($row)) { - $newRange .= $row; - } + $newRange = "{$newRange}{$column}{$row}"; $definedRange = substr($definedRange, 0, $offset) . $newRange . substr($definedRange, $offset + $length); } From 000e6088c98675882c595e3f8023a49410b34814 Mon Sep 17 00:00:00 2001 From: Patrick Brouwers Date: Wed, 3 Mar 2021 21:34:45 +0100 Subject: [PATCH 094/187] Reverted Scrutinzer fix in Xslx Reader listWorksheetInfo (#1895) --- CHANGELOG.md | 4 ++-- src/PhpSpreadsheet/Reader/Xlsx.php | 3 ++- tests/PhpSpreadsheetTests/Reader/XlsxTest.php | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 419869bd..b59bbe9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Nothing. +- Fixed issue with Xlsx@listWorksheetInfo not returning any data ## 1.17.1 - 2021-03-01 @@ -697,4 +697,4 @@ For a comprehensive list of all class changes, and a semi-automated migration pa ## Previous versions of PHPExcel -The changelog for the project when it was called PHPExcel is [still available](./CHANGELOG.PHPExcel.md). \ No newline at end of file +The changelog for the project when it was called PHPExcel is [still available](./CHANGELOG.PHPExcel.md). diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index bf754591..219a49fb 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -187,7 +187,8 @@ class Xlsx extends BaseReader ); if ($xmlWorkbook->sheets) { $dir = dirname($rel['Target']); - foreach ($xmlWorkbook->sheets->sheet->children() as $eleSheet) { + /** @var SimpleXMLElement $eleSheet */ + foreach ($xmlWorkbook->sheets->sheet as $eleSheet) { $tmpInfo = [ 'worksheetName' => (string) $eleSheet['name'], 'lastColumnLetter' => 'A', diff --git a/tests/PhpSpreadsheetTests/Reader/XlsxTest.php b/tests/PhpSpreadsheetTests/Reader/XlsxTest.php index b326c142..cb84a3b7 100644 --- a/tests/PhpSpreadsheetTests/Reader/XlsxTest.php +++ b/tests/PhpSpreadsheetTests/Reader/XlsxTest.php @@ -55,6 +55,25 @@ class XlsxTest extends TestCase } } + public function testListWorksheetInfo(): void + { + $filename = 'tests/data/Reader/XLSX/rowColumnAttributeTest.xlsx'; + $reader = new Xlsx(); + $actual = $reader->listWorksheetInfo($filename); + + $expected = [ + [ + 'worksheetName' => 'Sheet1', + 'lastColumnLetter' => 'F', + 'lastColumnIndex' => 5, + 'totalRows' => '6', + 'totalColumns' => 6, + ], + ]; + + self::assertEquals($expected, $actual); + } + public function testLoadXlsxRowColumnAttributes(): void { $filename = 'tests/data/Reader/XLSX/rowColumnAttributeTest.xlsx'; From d2a83b404a7a77766d765525e90570be85c7be48 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 3 Mar 2021 23:18:56 +0100 Subject: [PATCH 095/187] Statistical trends additional functions and unit tests (#1896) * PEARSON() and CORREL() are identical functions * Unit tests for GROWTH() function * Move GROWTH() function into Statistical\Trends Class --- .../Calculation/Calculation.php | 4 +-- .../Calculation/Statistical.php | 22 ++++--------- .../Calculation/Statistical/Trends.php | 32 +++++++++++++++++++ .../Functions/Statistical/GrowthTest.php | 32 +++++++++++++++++++ tests/data/Calculation/Statistical/GROWTH.php | 25 +++++++++++++++ 5 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php create mode 100644 tests/data/Calculation/Statistical/GROWTH.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 7fd07355..04b8ffab 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1206,7 +1206,7 @@ class Calculation ], 'GROWTH' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GROWTH'], + 'functionCall' => [Statistical\Trends::class, 'GROWTH'], 'argumentCount' => '1-4', ], 'HARMEAN' => [ @@ -1897,7 +1897,7 @@ class Calculation ], 'PEARSON' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CORREL'], + 'functionCall' => [Statistical\Trends::class, 'CORREL'], 'argumentCount' => '2', ], 'PERCENTILE' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index b2b9ad50..4b5c8094 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -1544,6 +1544,11 @@ class Statistical * * Returns values along a predicted exponential Trend * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::GROWTH() + * Use the GROWTH() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @param mixed[] $newValues Values of X for which we want to find Y @@ -1553,22 +1558,7 @@ class Statistical */ public static function GROWTH($yValues, $xValues = [], $newValues = [], $const = true) { - $yValues = Functions::flattenArray($yValues); - $xValues = Functions::flattenArray($xValues); - $newValues = Functions::flattenArray($newValues); - $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); - - $bestFitExponential = Trend::calculate(Trend::TREND_EXPONENTIAL, $yValues, $xValues, $const); - if (empty($newValues)) { - $newValues = $bestFitExponential->getXValues(); - } - - $returnArray = []; - foreach ($newValues as $xValue) { - $returnArray[0][] = $bestFitExponential->getValueOfYForX($xValue); - } - - return $returnArray; + return Trends::GROWTH($yValues, $xValues, $newValues, $const); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index 032b4625..23bffced 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -132,6 +132,38 @@ class Trends return $bestFitLinear->getValueOfYForX($xValue); } + /** + * GROWTH. + * + * Returns values along a predicted exponential Trend + * + * @param mixed[] $yValues Data Series Y + * @param mixed[] $xValues Data Series X + * @param mixed[] $newValues Values of X for which we want to find Y + * @param bool $const a logical value specifying whether to force the intersect to equal 0 + * + * @return array of float + */ + public static function GROWTH($yValues, $xValues = [], $newValues = [], $const = true) + { + $yValues = Functions::flattenArray($yValues); + $xValues = Functions::flattenArray($xValues); + $newValues = Functions::flattenArray($newValues); + $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); + + $bestFitExponential = Trend::calculate(Trend::TREND_EXPONENTIAL, $yValues, $xValues, $const); + if (empty($newValues)) { + $newValues = $bestFitExponential->getXValues(); + } + + $returnArray = []; + foreach ($newValues as $xValue) { + $returnArray[0][] = [$bestFitExponential->getValueOfYForX($xValue)]; + } + + return $returnArray; + } + /** * INTERCEPT. * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php new file mode 100644 index 00000000..ce4eef8a --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php @@ -0,0 +1,32 @@ + Date: Thu, 4 Mar 2021 21:45:56 +0100 Subject: [PATCH 096/187] Statistical refactoring - Confidence() and Trend() (#1898) - Move TREND() functions into the Statistical Trends class - Unit tests for TREND() - Create Confidence class for Statistical Confidence functions, and the CONFIDENCE() method --- .../Calculation/Calculation.php | 6 +-- .../Calculation/Statistical.php | 46 ++++++------------- .../Calculation/Statistical/Confidence.php | 41 +++++++++++++++++ .../Calculation/Statistical/Trends.php | 32 +++++++++++++ .../Functions/Statistical/GrowthTest.php | 5 +- .../Functions/Statistical/TrendTest.php | 33 +++++++++++++ tests/PhpSpreadsheetTests/Shared/FontTest.php | 15 +++--- tests/PhpSpreadsheetTests/Style/ColorTest.php | 15 +++--- tests/data/Calculation/Statistical/TREND.php | 34 ++++++++++++++ 9 files changed, 177 insertions(+), 50 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Confidence.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php create mode 100644 tests/data/Calculation/Statistical/TREND.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 04b8ffab..0d06f04e 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -579,12 +579,12 @@ class Calculation ], 'CONFIDENCE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CONFIDENCE'], + 'functionCall' => [Statistical\Confidence::class, 'CONFIDENCE'], 'argumentCount' => '3', ], 'CONFIDENCE.NORM' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CONFIDENCE'], + 'functionCall' => [Statistical\Confidence::class, 'CONFIDENCE'], 'argumentCount' => '3', ], 'CONFIDENCE.T' => [ @@ -2454,7 +2454,7 @@ class Calculation ], 'TREND' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'TREND'], + 'functionCall' => [Statistical\Trends::class, 'TREND'], 'argumentCount' => '1-4', ], 'TRIM' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 4b5c8094..8a9e3fea 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Averages; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Conditional; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Confidence; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Counts; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Maximum; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Minimum; @@ -832,6 +833,11 @@ class Statistical * * Returns the confidence interval for a population mean * + * @Deprecated 1.18.0 + * + * @see Statistical\Confidence::CONFIDENCE() + * Use the CONFIDENCE() method in the Statistical\Confidence class instead + * * @param float $alpha * @param float $stdDev Standard Deviation * @param float $size @@ -840,23 +846,7 @@ class Statistical */ public static function CONFIDENCE($alpha, $stdDev, $size) { - $alpha = Functions::flattenSingleValue($alpha); - $stdDev = Functions::flattenSingleValue($stdDev); - $size = Functions::flattenSingleValue($size); - - if ((is_numeric($alpha)) && (is_numeric($stdDev)) && (is_numeric($size))) { - $size = floor($size); - if (($alpha <= 0) || ($alpha >= 1)) { - return Functions::NAN(); - } - if (($stdDev <= 0) || ($size < 1)) { - return Functions::NAN(); - } - - return self::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); - } - - return Functions::VALUE(); + return Confidence::CONFIDENCE($alpha, $stdDev, $size); } /** @@ -2941,6 +2931,11 @@ class Statistical * * Returns values along a linear Trend * + * @Deprecated 1.18.0 + * + * @see Statistical\Trends::TREND() + * Use the TREND() method in the Statistical\Trends class instead + * * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @param mixed[] $newValues Values of X for which we want to find Y @@ -2950,22 +2945,7 @@ class Statistical */ public static function TREND($yValues, $xValues = [], $newValues = [], $const = true) { - $yValues = Functions::flattenArray($yValues); - $xValues = Functions::flattenArray($xValues); - $newValues = Functions::flattenArray($newValues); - $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); - - $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues, $const); - if (empty($newValues)) { - $newValues = $bestFitLinear->getXValues(); - } - - $returnArray = []; - foreach ($newValues as $xValue) { - $returnArray[0][] = $bestFitLinear->getValueOfYForX($xValue); - } - - return $returnArray; + return Trends::TREND($yValues, $xValues, $newValues, $const); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php new file mode 100644 index 00000000..c4c2a7dd --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php @@ -0,0 +1,41 @@ += 1)) { + return Functions::NAN(); + } + if (($stdDev <= 0) || ($size < 1)) { + return Functions::NAN(); + } + + return Statistical::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); + } + + return Functions::VALUE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index 23bffced..d06214de 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -388,4 +388,36 @@ class Trends return $bestFitLinear->getStdevOfResiduals(); } + + /** + * TREND. + * + * Returns values along a linear Trend + * + * @param mixed[] $yValues Data Series Y + * @param mixed[] $xValues Data Series X + * @param mixed[] $newValues Values of X for which we want to find Y + * @param bool $const a logical value specifying whether to force the intersect to equal 0 + * + * @return array of float + */ + public static function TREND($yValues, $xValues = [], $newValues = [], $const = true) + { + $yValues = Functions::flattenArray($yValues); + $xValues = Functions::flattenArray($xValues); + $newValues = Functions::flattenArray($newValues); + $const = ($const === null) ? true : (bool) Functions::flattenSingleValue($const); + + $bestFitLinear = Trend::calculate(Trend::TREND_LINEAR, $yValues, $xValues, $const); + if (empty($newValues)) { + $newValues = $bestFitLinear->getXValues(); + } + + $returnArray = []; + foreach ($newValues as $xValue) { + $returnArray[0][] = [$bestFitLinear->getValueOfYForX($xValue)]; + } + + return $returnArray; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php index ce4eef8a..6e1cf7bf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php @@ -17,10 +17,11 @@ class GrowthTest extends TestCase * @dataProvider providerGROWTH * * @param mixed $expectedResult + * @param mixed $yValues */ - public function testGROWTH($expectedResult, ...$args): void + public function testGROWTH($expectedResult, $yValues, ...$args): void { - $result = Statistical::GROWTH(...$args); + $result = Statistical::GROWTH($yValues, ...$args); self::assertEqualsWithDelta($expectedResult, $result[0], 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php new file mode 100644 index 00000000..b4f756b5 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php @@ -0,0 +1,33 @@ + Date: Sat, 6 Mar 2021 22:50:19 +0100 Subject: [PATCH 097/187] Trend unit tests (#1899) - Move TREND() functions into the Statistical Trends class - Unit tests for TREND() - Create Confidence class for Statistical Confidence functions --- .../Calculation/Statistical/Trends.php | 4 +- src/PhpSpreadsheet/Shared/Trend/BestFit.php | 65 ++++++----- .../Shared/Trend/ExponentialBestFit.php | 21 ++-- .../Shared/Trend/LinearBestFit.php | 5 +- .../Shared/Trend/LogarithmicBestFit.php | 23 ++-- .../Shared/Trend/PolynomialBestFit.php | 3 +- .../Shared/Trend/PowerBestFit.php | 35 +++--- src/PhpSpreadsheet/Shared/Trend/Trend.php | 9 +- .../Functions/Statistical/LogEstTest.php | 2 +- .../Shared/Trend/ExponentialBestFitTest.php | 49 +++++++++ .../Shared/Trend/LinearBestFitTest.php | 49 +++++++++ tests/data/Calculation/Statistical/LINEST.php | 104 ++++++++++++++---- tests/data/Calculation/Statistical/LOGEST.php | 54 +++++++++ .../data/Shared/Trend/ExponentialBestFit.php | 12 ++ tests/data/Shared/Trend/LinearBestFit.php | 20 ++++ 15 files changed, 344 insertions(+), 111 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php create mode 100644 tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php create mode 100644 tests/data/Shared/Trend/ExponentialBestFit.php create mode 100644 tests/data/Shared/Trend/LinearBestFit.php diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index d06214de..a1137cef 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -226,7 +226,7 @@ class Trends ], [ $bestFitLinear->getSlopeSE(), - $bestFitLinear->getIntersectSE(), + ($const === false) ? Functions::NA() : $bestFitLinear->getIntersectSE(), ], [ $bestFitLinear->getGoodnessOfFit(), @@ -293,7 +293,7 @@ class Trends ], [ $bestFitExponential->getSlopeSE(), - $bestFitExponential->getIntersectSE(), + ($const === false) ? Functions::NA() : $bestFitExponential->getIntersectSE(), ], [ $bestFitExponential->getGoodnessOfFit(), diff --git a/src/PhpSpreadsheet/Shared/Trend/BestFit.php b/src/PhpSpreadsheet/Shared/Trend/BestFit.php index c9499722..6d6f6283 100644 --- a/src/PhpSpreadsheet/Shared/Trend/BestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/BestFit.php @@ -348,13 +348,13 @@ class BestFit $bestFitY = $this->yBestFitValues[$xKey] = $this->getValueOfYForX($xValue); $SSres += ($this->yValues[$xKey] - $bestFitY) * ($this->yValues[$xKey] - $bestFitY); - if ($const) { + if ($const === true) { $SStot += ($this->yValues[$xKey] - $meanY) * ($this->yValues[$xKey] - $meanY); } else { $SStot += $this->yValues[$xKey] * $this->yValues[$xKey]; } $SScov += ($this->xValues[$xKey] - $meanX) * ($this->yValues[$xKey] - $meanY); - if ($const) { + if ($const === true) { $SSsex += ($this->xValues[$xKey] - $meanX) * ($this->xValues[$xKey] - $meanX); } else { $SSsex += $this->xValues[$xKey] * $this->xValues[$xKey]; @@ -362,7 +362,7 @@ class BestFit } $this->SSResiduals = $SSres; - $this->DFResiduals = $this->valueCount - 1 - $const; + $this->DFResiduals = $this->valueCount - 1 - ($const === true ? 1 : 0); if ($this->DFResiduals == 0.0) { $this->stdevOfResiduals = 0.0; @@ -395,27 +395,39 @@ class BestFit } } + private function sumSquares(array $values) + { + return array_sum( + array_map( + function ($value) { + return $value ** 2; + }, + $values + ) + ); + } + /** * @param float[] $yValues * @param float[] $xValues - * @param bool $const */ - protected function leastSquareFit(array $yValues, array $xValues, $const): void + protected function leastSquareFit(array $yValues, array $xValues, bool $const): void { // calculate sums - $x_sum = array_sum($xValues); - $y_sum = array_sum($yValues); - $meanX = $x_sum / $this->valueCount; - $meanY = $y_sum / $this->valueCount; - $mBase = $mDivisor = $xx_sum = $xy_sum = $yy_sum = 0.0; + $sumValuesX = array_sum($xValues); + $sumValuesY = array_sum($yValues); + $meanValueX = $sumValuesX / $this->valueCount; + $meanValueY = $sumValuesY / $this->valueCount; + $sumSquaresX = $this->sumSquares($xValues); + $sumSquaresY = $this->sumSquares($yValues); + $mBase = $mDivisor = 0.0; + $xy_sum = 0.0; for ($i = 0; $i < $this->valueCount; ++$i) { $xy_sum += $xValues[$i] * $yValues[$i]; - $xx_sum += $xValues[$i] * $xValues[$i]; - $yy_sum += $yValues[$i] * $yValues[$i]; - if ($const) { - $mBase += ($xValues[$i] - $meanX) * ($yValues[$i] - $meanY); - $mDivisor += ($xValues[$i] - $meanX) * ($xValues[$i] - $meanX); + if ($const === true) { + $mBase += ($xValues[$i] - $meanValueX) * ($yValues[$i] - $meanValueY); + $mDivisor += ($xValues[$i] - $meanValueX) * ($xValues[$i] - $meanValueX); } else { $mBase += $xValues[$i] * $yValues[$i]; $mDivisor += $xValues[$i] * $xValues[$i]; @@ -426,13 +438,9 @@ class BestFit $this->slope = $mBase / $mDivisor; // calculate intersect - if ($const) { - $this->intersect = $meanY - ($this->slope * $meanX); - } else { - $this->intersect = 0; - } + $this->intersect = ($const === true) ? $meanValueY - ($this->slope * $meanValueX) : 0.0; - $this->calculateGoodnessOfFit($x_sum, $y_sum, $xx_sum, $yy_sum, $xy_sum, $meanX, $meanY, $const); + $this->calculateGoodnessOfFit($sumValuesX, $sumValuesY, $sumSquaresX, $sumSquaresY, $xy_sum, $meanValueX, $meanValueY, $const); } /** @@ -440,23 +448,22 @@ class BestFit * * @param float[] $yValues The set of Y-values for this regression * @param float[] $xValues The set of X-values for this regression - * @param bool $const */ - public function __construct($yValues, $xValues = [], $const = true) + public function __construct($yValues, $xValues = []) { // Calculate number of points - $nY = count($yValues); - $nX = count($xValues); + $yValueCount = count($yValues); + $xValueCount = count($xValues); // Define X Values if necessary - if ($nX == 0) { - $xValues = range(1, $nY); - } elseif ($nY != $nX) { + if ($xValueCount === 0) { + $xValues = range(1, $yValueCount); + } elseif ($yValueCount !== $xValueCount) { // Ensure both arrays of points are the same size $this->error = true; } - $this->valueCount = $nY; + $this->valueCount = $yValueCount; $this->xValues = $xValues; $this->yValues = $yValues; } diff --git a/src/PhpSpreadsheet/Shared/Trend/ExponentialBestFit.php b/src/PhpSpreadsheet/Shared/Trend/ExponentialBestFit.php index 82866dee..eb8cd746 100644 --- a/src/PhpSpreadsheet/Shared/Trend/ExponentialBestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/ExponentialBestFit.php @@ -88,20 +88,17 @@ class ExponentialBestFit extends BestFit * * @param float[] $yValues The set of Y-values for this regression * @param float[] $xValues The set of X-values for this regression - * @param bool $const */ - private function exponentialRegression($yValues, $xValues, $const): void + private function exponentialRegression(array $yValues, array $xValues, bool $const): void { - foreach ($yValues as &$value) { - if ($value < 0.0) { - $value = 0 - log(abs($value)); - } elseif ($value > 0.0) { - $value = log($value); - } - } - unset($value); + $adjustedYValues = array_map( + function ($value) { + return ($value < 0.0) ? 0 - log(abs($value)) : log($value); + }, + $yValues + ); - $this->leastSquareFit($yValues, $xValues, $const); + $this->leastSquareFit($adjustedYValues, $xValues, $const); } /** @@ -116,7 +113,7 @@ class ExponentialBestFit extends BestFit parent::__construct($yValues, $xValues); if (!$this->error) { - $this->exponentialRegression($yValues, $xValues, $const); + $this->exponentialRegression($yValues, $xValues, (bool) $const); } } } diff --git a/src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php b/src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php index 26a562c5..65d6b4ff 100644 --- a/src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/LinearBestFit.php @@ -56,9 +56,8 @@ class LinearBestFit extends BestFit * * @param float[] $yValues The set of Y-values for this regression * @param float[] $xValues The set of X-values for this regression - * @param bool $const */ - private function linearRegression($yValues, $xValues, $const): void + private function linearRegression(array $yValues, array $xValues, bool $const): void { $this->leastSquareFit($yValues, $xValues, $const); } @@ -75,7 +74,7 @@ class LinearBestFit extends BestFit parent::__construct($yValues, $xValues); if (!$this->error) { - $this->linearRegression($yValues, $xValues, $const); + $this->linearRegression($yValues, $xValues, (bool) $const); } } } diff --git a/src/PhpSpreadsheet/Shared/Trend/LogarithmicBestFit.php b/src/PhpSpreadsheet/Shared/Trend/LogarithmicBestFit.php index c469067d..2366dc63 100644 --- a/src/PhpSpreadsheet/Shared/Trend/LogarithmicBestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/LogarithmicBestFit.php @@ -48,7 +48,7 @@ class LogarithmicBestFit extends BestFit $slope = $this->getSlope($dp); $intersect = $this->getIntersect($dp); - return 'Y = ' . $intersect . ' + ' . $slope . ' * log(X)'; + return 'Y = ' . $slope . ' * log(' . $intersect . ' * X)'; } /** @@ -56,20 +56,17 @@ class LogarithmicBestFit extends BestFit * * @param float[] $yValues The set of Y-values for this regression * @param float[] $xValues The set of X-values for this regression - * @param bool $const */ - private function logarithmicRegression($yValues, $xValues, $const): void + private function logarithmicRegression(array $yValues, array $xValues, bool $const): void { - foreach ($xValues as &$value) { - if ($value < 0.0) { - $value = 0 - log(abs($value)); - } elseif ($value > 0.0) { - $value = log($value); - } - } - unset($value); + $adjustedYValues = array_map( + function ($value) { + return ($value < 0.0) ? 0 - log(abs($value)) : log($value); + }, + $yValues + ); - $this->leastSquareFit($yValues, $xValues, $const); + $this->leastSquareFit($adjustedYValues, $xValues, $const); } /** @@ -84,7 +81,7 @@ class LogarithmicBestFit extends BestFit parent::__construct($yValues, $xValues); if (!$this->error) { - $this->logarithmicRegression($yValues, $xValues, $const); + $this->logarithmicRegression($yValues, $xValues, (bool) $const); } } } diff --git a/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php b/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php index d959eddb..1d34e81c 100644 --- a/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php @@ -178,9 +178,8 @@ class PolynomialBestFit extends BestFit * @param int $order Order of Polynomial for this regression * @param float[] $yValues The set of Y-values for this regression * @param float[] $xValues The set of X-values for this regression - * @param bool $const */ - public function __construct($order, $yValues, $xValues = [], $const = true) + public function __construct($order, $yValues, $xValues = []) { parent::__construct($yValues, $xValues); diff --git a/src/PhpSpreadsheet/Shared/Trend/PowerBestFit.php b/src/PhpSpreadsheet/Shared/Trend/PowerBestFit.php index c53eab63..cafd0115 100644 --- a/src/PhpSpreadsheet/Shared/Trend/PowerBestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/PowerBestFit.php @@ -72,28 +72,23 @@ class PowerBestFit extends BestFit * * @param float[] $yValues The set of Y-values for this regression * @param float[] $xValues The set of X-values for this regression - * @param bool $const */ - private function powerRegression($yValues, $xValues, $const): void + private function powerRegression(array $yValues, array $xValues, bool $const): void { - foreach ($xValues as &$value) { - if ($value < 0.0) { - $value = 0 - log(abs($value)); - } elseif ($value > 0.0) { - $value = log($value); - } - } - unset($value); - foreach ($yValues as &$value) { - if ($value < 0.0) { - $value = 0 - log(abs($value)); - } elseif ($value > 0.0) { - $value = log($value); - } - } - unset($value); + $adjustedYValues = array_map( + function ($value) { + return ($value < 0.0) ? 0 - log(abs($value)) : log($value); + }, + $yValues + ); + $adjustedXValues = array_map( + function ($value) { + return ($value < 0.0) ? 0 - log(abs($value)) : log($value); + }, + $xValues + ); - $this->leastSquareFit($yValues, $xValues, $const); + $this->leastSquareFit($adjustedYValues, $adjustedXValues, $const); } /** @@ -108,7 +103,7 @@ class PowerBestFit extends BestFit parent::__construct($yValues, $xValues); if (!$this->error) { - $this->powerRegression($yValues, $xValues, $const); + $this->powerRegression($yValues, $xValues, (bool) $const); } } } diff --git a/src/PhpSpreadsheet/Shared/Trend/Trend.php b/src/PhpSpreadsheet/Shared/Trend/Trend.php index 1b7b3901..d0a117cb 100644 --- a/src/PhpSpreadsheet/Shared/Trend/Trend.php +++ b/src/PhpSpreadsheet/Shared/Trend/Trend.php @@ -55,10 +55,9 @@ class Trend $nX = count($xValues); // Define X Values if necessary - if ($nX == 0) { + if ($nX === 0) { $xValues = range(1, $nY); - $nX = $nY; - } elseif ($nY != $nX) { + } elseif ($nY !== $nX) { // Ensure both arrays of points are the same size trigger_error('Trend(): Number of elements in coordinate arrays do not match.', E_USER_ERROR); } @@ -84,7 +83,7 @@ class Trend case self::TREND_POLYNOMIAL_6: if (!isset(self::$trendCache[$key])) { $order = substr($trendType, -1); - self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues, $const); + self::$trendCache[$key] = new PolynomialBestFit($order, $yValues, $xValues); } return self::$trendCache[$key]; @@ -100,7 +99,7 @@ class Trend if ($trendType != self::TREND_BEST_FIT_NO_POLY) { foreach (self::$trendTypePolynomialOrders as $trendMethod) { $order = substr($trendMethod, -1); - $bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues, $const); + $bestFit[$trendMethod] = new PolynomialBestFit($order, $yValues, $xValues); if ($bestFit[$trendMethod]->getError()) { unset($bestFit[$trendMethod]); } else { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php index 4d926f76..2b2d1ecf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php @@ -19,7 +19,7 @@ class LogEstTest extends TestCase public function testLOGEST($expectedResult, $yValues, $xValues, $const, $stats): void { $result = Statistical::LOGEST($yValues, $xValues, $const, $stats); - + //var_dump($result); $elements = count($expectedResult); for ($element = 0; $element < $elements; ++$element) { self::assertEqualsWithDelta($expectedResult[$element], $result[$element], 1E-12); diff --git a/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php b/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php new file mode 100644 index 00000000..32fa9d31 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php @@ -0,0 +1,49 @@ +getSlope(1); + self::assertEquals($expectedSlope[0], $slope); + $slope = $bestFit->getSlope(); + self::assertEquals($expectedSlope[1], $slope); + $intersect = $bestFit->getIntersect(1); + self::assertEquals($expectedIntersect[0], $intersect); + $intersect = $bestFit->getIntersect(); + self::assertEquals($expectedIntersect[1], $intersect); + + $equation = $bestFit->getEquation(2); + self::assertEquals($expectedEquation, $equation); + + self::assertSame($expectedGoodnessOfFit[0], $bestFit->getGoodnessOfFit(6)); + self::assertSame($expectedGoodnessOfFit[1], $bestFit->getGoodnessOfFit()); + } + + public function providerExponentialBestFit() + { + return require 'tests/data/Shared/Trend/ExponentialBestFit.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php b/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php new file mode 100644 index 00000000..02b82038 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php @@ -0,0 +1,49 @@ +getSlope(1); + self::assertEquals($expectedSlope[0], $slope); + $slope = $bestFit->getSlope(); + self::assertEquals($expectedSlope[1], $slope); + $intersect = $bestFit->getIntersect(1); + self::assertEquals($expectedIntersect[0], $intersect); + $intersect = $bestFit->getIntersect(); + self::assertEquals($expectedIntersect[1], $intersect); + + $equation = $bestFit->getEquation(2); + self::assertEquals($expectedEquation, $equation); + + self::assertSame($expectedGoodnessOfFit[0], $bestFit->getGoodnessOfFit(6)); + self::assertSame($expectedGoodnessOfFit[1], $bestFit->getGoodnessOfFit()); + } + + public function providerLinearBestFit() + { + return require 'tests/data/Shared/Trend/LinearBestFit.php'; + } +} diff --git a/tests/data/Calculation/Statistical/LINEST.php b/tests/data/Calculation/Statistical/LINEST.php index 9bd28ffe..ee5fdb0b 100644 --- a/tests/data/Calculation/Statistical/LINEST.php +++ b/tests/data/Calculation/Statistical/LINEST.php @@ -1,6 +1,22 @@ [ + // [ + // [-234.2371645, 2553.21066, 12529.76817, 27.64138737, 52317.83051], + // [13.26801148, 530.6691519, 400.0668382, 5.429374042, 12237.3616], + // [0.996747993, 970.5784629, '#N/A', '#N/A', '#N/A'], + // [459.7536742, 6, '#N/A', '#N/A', '#N/A'], + // [1732393319, 5652135.316, '#N/A', '#N/A', '#N/A'], + // ], + // [142000, 144000, 151000, 150000, 139000, 169000, 126000, 142900, 163000, 169000, 149000], + // [ + // [2310, 2, 2, 20], + // [2333, 2, 2, 12], + // [2356, 3, 1.5, 33], + // [2379, 3, 2, 43], + // [2402, 2, 3, 53], + // [2425, 4, 2, 23], + // [2448, 2, 1.5, 99], + // [2471, 2, 2, 34], + // [2494, 3, 3, 23], + // [2517, 4, 4, 55], + // [2540, 2, 3, 22], + // ], + // true, + // true, // ], - // [142000, 144000, 151000, 150000, 139000, 169000, 126000, 142900, 163000, 169000, 149000], - // [ - // [2310, 2, 2, 20], - // [2333, 2, 2, 12], - // [2356, 3, 1.5, 33], - // [2379, 3, 2, 43], - // [2402, 2, 3, 53], - // [2425, 4, 2, 23], - // [2448, 2, 1.5, 99], - // [2471, 2, 2, 34], - // [2494, 3, 3, 23], - // [2517, 4, 4, 55], - // [2540, 2, 3, 22], - // ], - // true, - // true, - // ], ]; diff --git a/tests/data/Calculation/Statistical/LOGEST.php b/tests/data/Calculation/Statistical/LOGEST.php index be9e4d72..bba7487b 100644 --- a/tests/data/Calculation/Statistical/LOGEST.php +++ b/tests/data/Calculation/Statistical/LOGEST.php @@ -1,6 +1,20 @@ [0.8, 0.813512072856517], + 'intersect' => [20.7, 20.671878197177865], + 'goodnessOfFit' => [0.904868, 0.9048681877346413], + 'equation' => 'Y = 20.67 * 0.81^X', + [3, 10, 3, 6, 8, 12, 1, 4, 9, 14], + [8, 2, 11, 6, 5, 4, 12, 9, 6, 1], + ], +]; diff --git a/tests/data/Shared/Trend/LinearBestFit.php b/tests/data/Shared/Trend/LinearBestFit.php new file mode 100644 index 00000000..b1be2f9a --- /dev/null +++ b/tests/data/Shared/Trend/LinearBestFit.php @@ -0,0 +1,20 @@ + [-1.1, -1.1064189189190], + 'intersect' => [14.1, 14.081081081081], + 'goodnessOfFit' => [0.873138, 0.8731378215564962], + 'equation' => 'Y = 14.08 + -1.11 * X', + [3, 10, 3, 6, 8, 12, 1, 4, 9, 14], + [8, 2, 11, 6, 5, 4, 12, 9, 6, 1], + ], + [ + 'slope' => [1.0, 1.0], + 'intersect' => [-2.0, -2.0], + 'goodnessOfFit' => [1.0, 1.0], + 'equation' => 'Y = -2 + 1 * X', + [1, 2, 3, 4, 5], + [3, 4, 5, 6, 7], + ], +]; From c4ed0ee7b0c646040a4310175362509cdeae40b5 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 7 Mar 2021 14:22:03 +0100 Subject: [PATCH 098/187] Minor scrutinizer improvements (#1906) * Minor scrutinizer improvements * Minor typing improvements --- .../Cell/AddressHelperTest.php | 12 ++++-- .../Cell/CoordinateTest.php | 21 +++++++--- .../Shared/CodePageTest.php | 5 ++- tests/PhpSpreadsheetTests/Shared/DateTest.php | 41 +++++++++++++------ 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php b/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php index 9b21767b..ffe0e05f 100644 --- a/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php @@ -26,9 +26,13 @@ class AddressHelperTest extends TestCase /** * @dataProvider providerR1C1ConversionToA1Relative */ - public function testR1C1ConversionToA1Relative(string $expectedValue, string $address, ?int $row = null, ?int $column = null): void - { - $args = [$address]; + public function testR1C1ConversionToA1Relative( + string $expectedValue, + string $address, + ?int $row = null, + ?int $column = null + ): void { + $args = []; if ($row !== null) { $args[] = $row; } @@ -36,7 +40,7 @@ class AddressHelperTest extends TestCase $args[] = $column; } - $actualValue = AddressHelper::convertToA1(...$args); + $actualValue = AddressHelper::convertToA1($address, ...$args); self::assertSame($expectedValue, $actualValue); } diff --git a/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php b/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php index 8e0e98a9..159af3b9 100644 --- a/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php @@ -232,10 +232,11 @@ class CoordinateTest extends TestCase * @dataProvider providerBuildRange * * @param mixed $expectedResult + * @param mixed $rangeSets */ - public function testBuildRange($expectedResult, ...$args): void + public function testBuildRange($expectedResult, $rangeSets): void { - $result = Coordinate::buildRange(...$args); + $result = Coordinate::buildRange($rangeSets); self::assertEquals($expectedResult, $result); } @@ -248,7 +249,16 @@ class CoordinateTest extends TestCase { $this->expectException(TypeError::class); - $cellRange = ''; + $cellRange = null; + Coordinate::buildRange($cellRange); + } + + public function testBuildRangeInvalid2(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('Range does not contain any information'); + + $cellRange = []; Coordinate::buildRange($cellRange); } @@ -342,10 +352,11 @@ class CoordinateTest extends TestCase * @dataProvider providerMergeRangesInCollection * * @param mixed $expectedResult + * @param mixed $rangeSets */ - public function testMergeRangesInCollection($expectedResult, ...$args): void + public function testMergeRangesInCollection($expectedResult, $rangeSets): void { - $result = Coordinate::mergeRangesInCollection(...$args); + $result = Coordinate::mergeRangesInCollection($rangeSets); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Shared/CodePageTest.php b/tests/PhpSpreadsheetTests/Shared/CodePageTest.php index 2bdbda72..eb121889 100644 --- a/tests/PhpSpreadsheetTests/Shared/CodePageTest.php +++ b/tests/PhpSpreadsheetTests/Shared/CodePageTest.php @@ -12,10 +12,11 @@ class CodePageTest extends TestCase * @dataProvider providerCodePage * * @param mixed $expectedResult + * @param mixed $codePageIndex */ - public function testCodePageNumberToName($expectedResult, ...$args): void + public function testCodePageNumberToName($expectedResult, $codePageIndex): void { - $result = CodePage::numberToName(...$args); + $result = CodePage::numberToName($codePageIndex); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Shared/DateTest.php b/tests/PhpSpreadsheetTests/Shared/DateTest.php index 550e2f6a..4ab7461b 100644 --- a/tests/PhpSpreadsheetTests/Shared/DateTest.php +++ b/tests/PhpSpreadsheetTests/Shared/DateTest.php @@ -39,7 +39,7 @@ class DateTest extends TestCase public function testSetExcelCalendarWithInvalidValue(): void { - $unsupportedCalendar = '2012'; + $unsupportedCalendar = 2012; $result = Date::setExcelCalendar($unsupportedCalendar); self::assertFalse($result); } @@ -48,15 +48,16 @@ class DateTest extends TestCase * @dataProvider providerDateTimeExcelToTimestamp1900 * * @param mixed $expectedResult + * @param mixed $excelDateTimeValue */ - public function testDateTimeExcelToTimestamp1900($expectedResult, ...$args): void + public function testDateTimeExcelToTimestamp1900($expectedResult, $excelDateTimeValue): void { if (is_numeric($expectedResult) && ($expectedResult > PHP_INT_MAX || $expectedResult < PHP_INT_MIN)) { self::markTestSkipped('Test invalid on 32-bit system.'); } Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - $result = Date::excelToTimestamp(...$args); + $result = Date::excelToTimestamp($excelDateTimeValue); self::assertEquals($expectedResult, $result); } @@ -69,12 +70,13 @@ class DateTest extends TestCase * @dataProvider providerDateTimeTimestampToExcel1900 * * @param mixed $expectedResult + * @param mixed $unixTimestamp */ - public function testDateTimeTimestampToExcel1900($expectedResult, ...$args): void + public function testDateTimeTimestampToExcel1900($expectedResult, $unixTimestamp): void { Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - $result = Date::timestampToExcel(...$args); + $result = Date::timestampToExcel($unixTimestamp); self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } @@ -87,12 +89,13 @@ class DateTest extends TestCase * @dataProvider providerDateTimeDateTimeToExcel * * @param mixed $expectedResult + * @param mixed $dateTimeObject */ - public function testDateTimeDateTimeToExcel($expectedResult, ...$args): void + public function testDateTimeDateTimeToExcel($expectedResult, $dateTimeObject): void { Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - $result = Date::dateTimeToExcel(...$args); + $result = Date::dateTimeToExcel($dateTimeObject); self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } @@ -123,15 +126,16 @@ class DateTest extends TestCase * @dataProvider providerDateTimeExcelToTimestamp1904 * * @param mixed $expectedResult + * @param mixed $excelDateTimeValue */ - public function testDateTimeExcelToTimestamp1904($expectedResult, ...$args): void + public function testDateTimeExcelToTimestamp1904($expectedResult, $excelDateTimeValue): void { if (is_numeric($expectedResult) && ($expectedResult > PHP_INT_MAX || $expectedResult < PHP_INT_MIN)) { self::markTestSkipped('Test invalid on 32-bit system.'); } Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - $result = Date::excelToTimestamp(...$args); + $result = Date::excelToTimestamp($excelDateTimeValue); self::assertEquals($expectedResult, $result); } @@ -144,12 +148,13 @@ class DateTest extends TestCase * @dataProvider providerDateTimeTimestampToExcel1904 * * @param mixed $expectedResult + * @param mixed $unixTimestamp */ - public function testDateTimeTimestampToExcel1904($expectedResult, ...$args): void + public function testDateTimeTimestampToExcel1904($expectedResult, $unixTimestamp): void { Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - $result = Date::timestampToExcel(...$args); + $result = Date::timestampToExcel($unixTimestamp); self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } @@ -178,15 +183,17 @@ class DateTest extends TestCase * @dataProvider providerDateTimeExcelToTimestamp1900Timezone * * @param mixed $expectedResult + * @param mixed $excelDateTimeValue + * @param mixed $timezone */ - public function testDateTimeExcelToTimestamp1900Timezone($expectedResult, ...$args): void + public function testDateTimeExcelToTimestamp1900Timezone($expectedResult, $excelDateTimeValue, $timezone): void { if (is_numeric($expectedResult) && ($expectedResult > PHP_INT_MAX || $expectedResult < PHP_INT_MIN)) { self::markTestSkipped('Test invalid on 32-bit system.'); } Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - $result = Date::excelToTimestamp(...$args); + $result = Date::excelToTimestamp($excelDateTimeValue, $timezone); self::assertEquals($expectedResult, $result); } @@ -202,29 +209,37 @@ class DateTest extends TestCase self::assertTrue((bool) Date::stringToExcel('2019-02-28')); self::assertTrue((bool) Date::stringToExcel('2019-02-28 11:18')); self::assertFalse(Date::stringToExcel('2019-02-28 11:71')); + $date = Date::PHPToExcel('2020-01-01'); self::assertEquals(43831.0, $date); + $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setCellValue('B1', 'x'); $val = $sheet->getCell('B1')->getValue(); self::assertFalse(Date::timestampToExcel($val)); + $cell = $sheet->getCell('A1'); self::assertNotNull($cell); + $cell->setValue($date); $sheet->getStyle('A1') ->getNumberFormat() ->setFormatCode(NumberFormat::FORMAT_DATE_DATETIME); self::assertTrue(null !== $cell && Date::isDateTime($cell)); + $cella2 = $sheet->getCell('A2'); self::assertNotNull($cella2); + $cella2->setValue('=A1+2'); $sheet->getStyle('A2') ->getNumberFormat() ->setFormatCode(NumberFormat::FORMAT_DATE_DATETIME); self::assertTrue(null !== $cella2 && Date::isDateTime($cella2)); + $cella3 = $sheet->getCell('A3'); self::assertNotNull($cella3); + $cella3->setValue('=A1+4'); $sheet->getStyle('A3') ->getNumberFormat() From f81ffd9a4fe7b173c385c180812b6b3a3e3aa1b8 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 8 Mar 2021 12:54:06 +0100 Subject: [PATCH 099/187] Additional argument validation for LEFT(), MID() and RIGHT() text functions (#1909) * Additional argument validation for LEFT(), MID() and RIGHT() text functions --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Calculation/TextData.php | 10 +++------- tests/data/Calculation/TextData/LEFT.php | 10 ++++++++++ tests/data/Calculation/TextData/MID.php | 14 +++++++++++++- tests/data/Calculation/TextData/RIGHT.php | 10 ++++++++++ 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b59bbe9d..2474e26d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed - Fixed issue with Xlsx@listWorksheetInfo not returning any data +- Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640) ## 1.17.1 - 2021-03-01 diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index cea15fdc..b886ce08 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -299,7 +299,7 @@ class TextData $value = Functions::flattenSingleValue($value); $chars = Functions::flattenSingleValue($chars); - if ($chars < 0) { + if (!is_numeric($chars) || $chars < 0) { return Functions::VALUE(); } @@ -325,7 +325,7 @@ class TextData $start = Functions::flattenSingleValue($start); $chars = Functions::flattenSingleValue($chars); - if (($start < 1) || ($chars < 0)) { + if (!is_numeric($start) || $start < 1 || !is_numeric($chars) || $chars < 0) { return Functions::VALUE(); } @@ -333,10 +333,6 @@ class TextData $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); } - if (empty($chars)) { - return ''; - } - return mb_substr($value, --$start, $chars, 'UTF-8'); } @@ -353,7 +349,7 @@ class TextData $value = Functions::flattenSingleValue($value); $chars = Functions::flattenSingleValue($chars); - if ($chars < 0) { + if (!is_numeric($chars) || $chars < 0) { return Functions::VALUE(); } diff --git a/tests/data/Calculation/TextData/LEFT.php b/tests/data/Calculation/TextData/LEFT.php index 914d16be..96702f6b 100644 --- a/tests/data/Calculation/TextData/LEFT.php +++ b/tests/data/Calculation/TextData/LEFT.php @@ -16,6 +16,16 @@ return [ 'QWERTYUIOP', -1, ], + [ + '#VALUE!', + 'QWERTYUIOP', + 'NaN', + ], + [ + '#VALUE!', + 'QWERTYUIOP', + null, + ], [ 'ABC', 'ABCDEFGHI', diff --git a/tests/data/Calculation/TextData/MID.php b/tests/data/Calculation/TextData/MID.php index 2a59373b..71d90e8b 100644 --- a/tests/data/Calculation/TextData/MID.php +++ b/tests/data/Calculation/TextData/MID.php @@ -26,7 +26,19 @@ return [ -1, ], [ - '', + '#VALUE!', + 'QWERTYUIOP', + 'NaN', + 1, + ], + [ + '#VALUE!', + 'QWERTYUIOP', + 2, + 'NaN', + ], + [ + '#VALUE!', 'QWERTYUIOP', 5, ], diff --git a/tests/data/Calculation/TextData/RIGHT.php b/tests/data/Calculation/TextData/RIGHT.php index 78ea6a69..95dfe96e 100644 --- a/tests/data/Calculation/TextData/RIGHT.php +++ b/tests/data/Calculation/TextData/RIGHT.php @@ -16,6 +16,16 @@ return [ 'QWERTYUIOP', -1, ], + [ + '#VALUE!', + 'QWERTYUIOP', + 'NaN', + ], + [ + '#VALUE!', + 'QWERTYUIOP', + null, + ], [ 'GHI', 'ABCDEFGHI', From 70f372d88c9c6bea223bfb9c791c5c78fbbbbd26 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 10 Mar 2021 21:18:33 +0100 Subject: [PATCH 100/187] Start refactoring the Lookup and Reference functions (#1912) * Start refactoring the Lookup and Reference functions - COLUMN(), COLUMNS(), ROW() and ROWS() - LOOKUP(), VLOOKUP() and HLOOKUP() - Refactor TRANSPOSE() and ADDRESS() functions into their own classes * Additional unit tests - LOOKUP() - TRANSPOSE() - ADDRESS() --- .../Calculation/Calculation.php | 20 +- src/PhpSpreadsheet/Calculation/LookupRef.php | 433 ++++-------------- .../Calculation/LookupRef/Address.php | 97 ++++ .../Calculation/LookupRef/HLookup.php | 86 ++++ .../Calculation/LookupRef/Lookup.php | 105 +++++ .../Calculation/LookupRef/LookupBase.php | 48 ++ .../Calculation/LookupRef/Matrix.php | 33 ++ .../LookupRef/RowColumnInformation.php | 172 +++++++ .../Calculation/LookupRef/VLookup.php | 105 +++++ .../Functions/LookupRef/AddressTest.php | 31 ++ .../Functions/LookupRef/ColumnTest.php | 17 +- .../Functions/LookupRef/RowTest.php | 17 +- .../Functions/LookupRef/TransposeTest.php | 32 ++ .../Cell/DefaultValueBinderTest.php | 5 +- tests/data/Calculation/LookupRef/ADDRESS.php | 56 +++ tests/data/Calculation/LookupRef/COLUMN.php | 20 + tests/data/Calculation/LookupRef/HLOOKUP.php | 20 + tests/data/Calculation/LookupRef/LOOKUP.php | 42 +- tests/data/Calculation/LookupRef/ROW.php | 16 + .../data/Calculation/LookupRef/TRANSPOSE.php | 32 ++ tests/data/Calculation/LookupRef/VLOOKUP.php | 29 +- 21 files changed, 1041 insertions(+), 375 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/Address.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php create mode 100644 tests/data/Calculation/LookupRef/ADDRESS.php create mode 100644 tests/data/Calculation/LookupRef/TRANSPOSE.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 0d06f04e..3adcf243 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -263,7 +263,7 @@ class Calculation ], 'ADDRESS' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'cellAddress'], + 'functionCall' => [LookupRef\Address::class, 'cell'], 'argumentCount' => '2-5', ], 'AGGREGATE' => [ @@ -543,13 +543,14 @@ class Calculation ], 'COLUMN' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'COLUMN'], + 'functionCall' => [LookupRef\RowColumnInformation::class, 'COLUMN'], 'argumentCount' => '-1', + 'passCellReference' => true, 'passByReference' => [true], ], 'COLUMNS' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'COLUMNS'], + 'functionCall' => [LookupRef\RowColumnInformation::class, 'COLUMNS'], 'argumentCount' => '1', ], 'COMBIN' => [ @@ -1231,7 +1232,7 @@ class Calculation ], 'HLOOKUP' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'HLOOKUP'], + 'functionCall' => [LookupRef\HLookup::class, 'lookup'], 'argumentCount' => '3,4', ], 'HOUR' => [ @@ -1605,7 +1606,7 @@ class Calculation ], 'LOOKUP' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'LOOKUP'], + 'functionCall' => [LookupRef\Lookup::class, 'lookup'], 'argumentCount' => '2,3', ], 'LOWER' => [ @@ -2127,13 +2128,14 @@ class Calculation ], 'ROW' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'ROW'], + 'functionCall' => [LookupRef\RowColumnInformation::class, 'ROW'], 'argumentCount' => '-1', + 'passCellReference' => true, 'passByReference' => [true], ], 'ROWS' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'ROWS'], + 'functionCall' => [LookupRef\RowColumnInformation::class, 'ROWS'], 'argumentCount' => '1', ], 'RRI' => [ @@ -2449,7 +2451,7 @@ class Calculation ], 'TRANSPOSE' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'TRANSPOSE'], + 'functionCall' => [LookupRef\Matrix::class, 'transpose'], 'argumentCount' => '1', ], 'TREND' => [ @@ -2559,7 +2561,7 @@ class Calculation ], 'VLOOKUP' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'VLOOKUP'], + 'functionCall' => [LookupRef\VLookup::class, 'lookup'], 'argumentCount' => '3,4', ], 'WEBSERVICE' => [ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index 45aa9239..39823a20 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -2,6 +2,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Address; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\HLookup; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Lookup; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Matrix; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\RowColumnInformation; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\VLookup; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; @@ -17,15 +23,19 @@ class LookupRef * Excel Function: * =ADDRESS(row, column, [relativity], [referenceStyle], [sheetText]) * + * @Deprecated 1.18.0 + * + * @see Use the cell() method in the LookupRef\Address class instead + * * @param mixed $row Row number to use in the cell reference * @param mixed $column Column number to use in the cell reference * @param int $relativity Flag indicating the type of reference to return * 1 or omitted Absolute - * 2 Absolute row; relative column - * 3 Relative row; absolute column - * 4 Relative + * 2 Absolute row; relative column + * 3 Relative row; absolute column + * 4 Relative * @param bool $referenceStyle A logical value that specifies the A1 or R1C1 reference style. - * TRUE or omitted CELL_ADDRESS returns an A1-style reference + * TRUE or omitted CELL_ADDRESS returns an A1-style reference * FALSE CELL_ADDRESS returns an R1C1-style reference * @param string $sheetText Optional Name of worksheet to use * @@ -33,87 +43,33 @@ class LookupRef */ public static function cellAddress($row, $column, $relativity = 1, $referenceStyle = true, $sheetText = '') { - $row = Functions::flattenSingleValue($row); - $column = Functions::flattenSingleValue($column); - $relativity = Functions::flattenSingleValue($relativity); - $sheetText = Functions::flattenSingleValue($sheetText); - - if (($row < 1) || ($column < 1)) { - return Functions::VALUE(); - } - - if ($sheetText > '') { - if (strpos($sheetText, ' ') !== false) { - $sheetText = "'" . $sheetText . "'"; - } - $sheetText .= '!'; - } - if ((!is_bool($referenceStyle)) || $referenceStyle) { - $rowRelative = $columnRelative = '$'; - $column = Coordinate::stringFromColumnIndex($column); - if (($relativity == 2) || ($relativity == 4)) { - $columnRelative = ''; - } - if (($relativity == 3) || ($relativity == 4)) { - $rowRelative = ''; - } - - return $sheetText . $columnRelative . $column . $rowRelative . $row; - } - if (($relativity == 2) || ($relativity == 4)) { - $column = '[' . $column . ']'; - } - if (($relativity == 3) || ($relativity == 4)) { - $row = '[' . $row . ']'; - } - - return $sheetText . 'R' . $row . 'C' . $column; + return Address::cell($row, $column, $relativity, $referenceStyle, $sheetText); } /** * COLUMN. * * Returns the column number of the given cell reference - * If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array. - * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the - * reference of the cell in which the COLUMN function appears; otherwise this function returns 0. + * If the cell reference is a range of cells, COLUMN returns the column numbers of each column + * in the reference as a horizontal array. + * If cell reference is omitted, and the function is being called through the calculation engine, + * then it is assumed to be the reference of the cell in which the COLUMN function appears; + * otherwise this function returns 1. * * Excel Function: * =COLUMN([cellAddress]) * + * @Deprecated 1.18.0 + * + * @see Use the COLUMN() method in the LookupRef\RowColumnInformation class instead + * * @param null|array|string $cellAddress A reference to a range of cells for which you want the column numbers * * @return int|int[] */ - public static function COLUMN($cellAddress = null) + public static function COLUMN($cellAddress = null, ?Cell $cell = null) { - if ($cellAddress === null || trim($cellAddress) === '') { - return 0; - } - - if (is_array($cellAddress)) { - foreach ($cellAddress as $columnKey => $value) { - $columnKey = preg_replace('/[^a-z]/i', '', $columnKey); - - return (int) Coordinate::columnIndexFromString($columnKey); - } - } else { - [$sheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - if (strpos($cellAddress, ':') !== false) { - [$startAddress, $endAddress] = explode(':', $cellAddress); - $startAddress = preg_replace('/[^a-z]/i', '', $startAddress); - $endAddress = preg_replace('/[^a-z]/i', '', $endAddress); - $returnValue = []; - do { - $returnValue[] = (int) Coordinate::columnIndexFromString($startAddress); - } while ($startAddress++ != $endAddress); - - return $returnValue; - } - $cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress); - - return (int) Coordinate::columnIndexFromString($cellAddress); - } + return RowColumnInformation::COLUMN($cellAddress, $cell); } /** @@ -124,73 +80,44 @@ class LookupRef * Excel Function: * =COLUMNS(cellAddress) * - * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells for which you want the number of columns + * @Deprecated 1.18.0 + * + * @see Use the COLUMNS() method in the LookupRef\RowColumnInformation class instead + * + * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells + * for which you want the number of columns * * @return int|string The number of columns in cellAddress, or a string if arguments are invalid */ public static function COLUMNS($cellAddress = null) { - if ($cellAddress === null || $cellAddress === '') { - return 1; - } elseif (!is_array($cellAddress)) { - return Functions::VALUE(); - } - - reset($cellAddress); - $isMatrix = (is_numeric(key($cellAddress))); - [$columns, $rows] = Calculation::getMatrixDimensions($cellAddress); - - if ($isMatrix) { - return $rows; - } - - return $columns; + return RowColumnInformation::COLUMNS($cellAddress); } /** * ROW. * * Returns the row number of the given cell reference - * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array. - * If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the - * reference of the cell in which the ROW function appears; otherwise this function returns 0. + * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference + * as a vertical array. + * If cell reference is omitted, and the function is being called through the calculation engine, + * then it is assumed to be the reference of the cell in which the ROW function appears; + * otherwise this function returns 1. * * Excel Function: * =ROW([cellAddress]) * + * @Deprecated 1.18.0 + * + * @see Use the ROW() method in the LookupRef\RowColumnInformation class instead + * * @param null|array|string $cellAddress A reference to a range of cells for which you want the row numbers * * @return int|mixed[]|string */ - public static function ROW($cellAddress = null) + public static function ROW($cellAddress = null, ?Cell $cell = null) { - if ($cellAddress === null || trim($cellAddress) === '') { - return 0; - } - - if (is_array($cellAddress)) { - foreach ($cellAddress as $columnKey => $rowValue) { - foreach ($rowValue as $rowKey => $cellValue) { - return (int) preg_replace('/\D/', '', $rowKey); - } - } - } else { - [$sheet, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - if (strpos($cellAddress, ':') !== false) { - [$startAddress, $endAddress] = explode(':', $cellAddress); - $startAddress = preg_replace('/\D/', '', $startAddress); - $endAddress = preg_replace('/\D/', '', $endAddress); - $returnValue = []; - do { - $returnValue[][] = (int) $startAddress; - } while ($startAddress++ != $endAddress); - - return $returnValue; - } - [$cellAddress] = explode(':', $cellAddress); - - return (int) preg_replace('/\D/', '', $cellAddress); - } + return RowColumnInformation::ROW($cellAddress, $cell); } /** @@ -201,27 +128,18 @@ class LookupRef * Excel Function: * =ROWS(cellAddress) * - * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows + * @Deprecated 1.18.0 + * + * @see Use the ROWS() method in the LookupRef\RowColumnInformation class instead + * + * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells + * for which you want the number of rows * * @return int|string The number of rows in cellAddress, or a string if arguments are invalid */ public static function ROWS($cellAddress = null) { - if ($cellAddress === null || $cellAddress === '') { - return 1; - } elseif (!is_array($cellAddress)) { - return Functions::VALUE(); - } - - reset($cellAddress); - $isMatrix = (is_numeric(key($cellAddress))); - [$columns, $rows] = Calculation::getMatrixDimensions($cellAddress); - - if ($isMatrix) { - return $columns; - } - - return $rows; + return RowColumnInformation::ROWS($cellAddress); } /** @@ -669,204 +587,74 @@ class LookupRef /** * TRANSPOSE. * + * @Deprecated 1.18.0 + * + * @see Use the transpose() method in the LookupRef\Matrix class instead + * * @param array $matrixData A matrix of values * * @return array * - * Unlike the Excel TRANSPOSE function, which will only work on a single row or column, this function will transpose a full matrix + * Unlike the Excel TRANSPOSE function, which will only work on a single row or column, + * this function will transpose a full matrix */ public static function TRANSPOSE($matrixData) { - $returnMatrix = []; - if (!is_array($matrixData)) { - $matrixData = [[$matrixData]]; - } - - $column = 0; - foreach ($matrixData as $matrixRow) { - $row = 0; - foreach ($matrixRow as $matrixCell) { - $returnMatrix[$row][$column] = $matrixCell; - ++$row; - } - ++$column; - } - - return $returnMatrix; - } - - private static function vlookupSort($a, $b) - { - reset($a); - $firstColumn = key($a); - $aLower = StringHelper::strToLower($a[$firstColumn]); - $bLower = StringHelper::strToLower($b[$firstColumn]); - if ($aLower == $bLower) { - return 0; - } - - return ($aLower < $bLower) ? -1 : 1; + return Matrix::transpose($matrixData); } /** * VLOOKUP - * The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value in the same row based on the index_number. + * The VLOOKUP function searches for value in the left-most column of lookup_array and returns the value + * in the same row based on the index_number. + * + * @Deprecated 1.18.0 + * + * @see Use the lookup() method in the LookupRef\VLookup class instead * * @param mixed $lookup_value The value that you want to match in lookup_array * @param mixed $lookup_array The range of cells being searched - * @param mixed $index_number The column number in table_array from which the matching value must be returned. The first column is 1. + * @param mixed $index_number The column number in table_array from which the matching value must be returned. + * The first column is 1. * @param mixed $not_exact_match determines if you are looking for an exact match based on lookup_value * * @return mixed The value of the found cell */ public static function VLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match = true) { - $lookup_value = Functions::flattenSingleValue($lookup_value); - $index_number = Functions::flattenSingleValue($index_number); - $not_exact_match = Functions::flattenSingleValue($not_exact_match); - - // index_number must be greater than or equal to 1 - if ($index_number < 1) { - return Functions::VALUE(); - } - - // index_number must be less than or equal to the number of columns in lookup_array - if ((!is_array($lookup_array)) || (empty($lookup_array))) { - return Functions::REF(); - } - $f = array_keys($lookup_array); - $firstRow = array_pop($f); - if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array[$firstRow]))) { - return Functions::REF(); - } - $columnKeys = array_keys($lookup_array[$firstRow]); - $returnColumn = $columnKeys[--$index_number]; - $firstColumn = array_shift($columnKeys); - - if (!$not_exact_match) { - uasort($lookup_array, ['self', 'vlookupSort']); - } - - $lookupLower = StringHelper::strToLower($lookup_value); - $rowNumber = $rowValue = false; - foreach ($lookup_array as $rowKey => $rowData) { - $firstLower = StringHelper::strToLower($rowData[$firstColumn]); - - // break if we have passed possible keys - if ( - (is_numeric($lookup_value) && is_numeric($rowData[$firstColumn]) && ($rowData[$firstColumn] > $lookup_value)) || - (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn]) && ($firstLower > $lookupLower)) - ) { - break; - } - // remember the last key, but only if datatypes match - if ( - (is_numeric($lookup_value) && is_numeric($rowData[$firstColumn])) || - (!is_numeric($lookup_value) && !is_numeric($rowData[$firstColumn])) - ) { - if ($not_exact_match) { - $rowNumber = $rowKey; - - continue; - } elseif ( - ($firstLower == $lookupLower) - // Spreadsheets software returns first exact match, - // we have sorted and we might have broken key orders - // we want the first one (by its initial index) - && (($rowNumber == false) || ($rowKey < $rowNumber)) - ) { - $rowNumber = $rowKey; - } - } - } - - if ($rowNumber !== false) { - // return the appropriate value - return $lookup_array[$rowNumber][$returnColumn]; - } - - return Functions::NA(); + return VLookup::lookup($lookup_value, $lookup_array, $index_number, $not_exact_match); } /** * HLOOKUP - * The HLOOKUP function searches for value in the top-most row of lookup_array and returns the value in the same column based on the index_number. + * The HLOOKUP function searches for value in the top-most row of lookup_array and returns the value + * in the same column based on the index_number. + * + * @Deprecated 1.18.0 + * + * @see Use the lookup() method in the LookupRef\HLookup class instead * * @param mixed $lookup_value The value that you want to match in lookup_array * @param mixed $lookup_array The range of cells being searched - * @param mixed $index_number The row number in table_array from which the matching value must be returned. The first row is 1. + * @param mixed $index_number The row number in table_array from which the matching value must be returned. + * The first row is 1. * @param mixed $not_exact_match determines if you are looking for an exact match based on lookup_value * * @return mixed The value of the found cell */ public static function HLOOKUP($lookup_value, $lookup_array, $index_number, $not_exact_match = true) { - $lookup_value = Functions::flattenSingleValue($lookup_value); - $index_number = Functions::flattenSingleValue($index_number); - $not_exact_match = Functions::flattenSingleValue($not_exact_match); - - // index_number must be greater than or equal to 1 - if ($index_number < 1) { - return Functions::VALUE(); - } - - // index_number must be less than or equal to the number of columns in lookup_array - if ((!is_array($lookup_array)) || (empty($lookup_array))) { - return Functions::REF(); - } - $f = array_keys($lookup_array); - $firstRow = reset($f); - if ((!is_array($lookup_array[$firstRow])) || ($index_number > count($lookup_array))) { - return Functions::REF(); - } - - $firstkey = $f[0] - 1; - $returnColumn = $firstkey + $index_number; - $firstColumn = array_shift($f); - $rowNumber = null; - foreach ($lookup_array[$firstColumn] as $rowKey => $rowData) { - // break if we have passed possible keys - $bothNumeric = is_numeric($lookup_value) && is_numeric($rowData); - $bothNotNumeric = !is_numeric($lookup_value) && !is_numeric($rowData); - $lookupLower = StringHelper::strToLower($lookup_value); - $rowDataLower = StringHelper::strToLower($rowData); - - if ( - $not_exact_match && ( - ($bothNumeric && $rowData > $lookup_value) || - ($bothNotNumeric && $rowDataLower > $lookupLower) - ) - ) { - break; - } - - // Remember the last key, but only if datatypes match (as in VLOOKUP) - if ($bothNumeric || $bothNotNumeric) { - if ($not_exact_match) { - $rowNumber = $rowKey; - - continue; - } elseif ( - $rowDataLower === $lookupLower - && ($rowNumber === null || $rowKey < $rowNumber) - ) { - $rowNumber = $rowKey; - } - } - } - - if ($rowNumber !== null) { - // otherwise return the appropriate value - return $lookup_array[$returnColumn][$rowNumber]; - } - - return Functions::NA(); + return HLookup::lookup($lookup_value, $lookup_array, $index_number, $not_exact_match); } /** * LOOKUP * The LOOKUP function searches for value either from a one-row or one-column range or from an array. * + * @Deprecated 1.18.0 + * + * @see Use the lookup() method in the LookupRef\Lookup class instead + * * @param mixed $lookup_value The value that you want to match in lookup_array * @param mixed $lookup_vector The range of cells being searched * @param null|mixed $result_vector The column from which the matching value must be returned @@ -875,66 +663,7 @@ class LookupRef */ public static function LOOKUP($lookup_value, $lookup_vector, $result_vector = null) { - $lookup_value = Functions::flattenSingleValue($lookup_value); - - if (!is_array($lookup_vector)) { - return Functions::NA(); - } - $hasResultVector = isset($result_vector); - $lookupRows = count($lookup_vector); - $l = array_keys($lookup_vector); - $l = array_shift($l); - $lookupColumns = count($lookup_vector[$l]); - // we correctly orient our results - if (($lookupRows === 1 && $lookupColumns > 1) || (!$hasResultVector && $lookupRows === 2 && $lookupColumns !== 2)) { - $lookup_vector = self::TRANSPOSE($lookup_vector); - $lookupRows = count($lookup_vector); - $l = array_keys($lookup_vector); - $lookupColumns = count($lookup_vector[array_shift($l)]); - } - - if ($result_vector === null) { - $result_vector = $lookup_vector; - } - $resultRows = count($result_vector); - $l = array_keys($result_vector); - $l = array_shift($l); - $resultColumns = count($result_vector[$l]); - // we correctly orient our results - if ($resultRows === 1 && $resultColumns > 1) { - $result_vector = self::TRANSPOSE($result_vector); - $resultRows = count($result_vector); - $r = array_keys($result_vector); - $resultColumns = count($result_vector[array_shift($r)]); - } - - if ($lookupRows === 2 && !$hasResultVector) { - $result_vector = array_pop($lookup_vector); - $lookup_vector = array_shift($lookup_vector); - } - - if ($lookupColumns !== 2) { - foreach ($lookup_vector as &$value) { - if (is_array($value)) { - $k = array_keys($value); - $key1 = $key2 = array_shift($k); - ++$key2; - $dataValue1 = $value[$key1]; - } else { - $key1 = 0; - $key2 = 1; - $dataValue1 = $value; - } - $dataValue2 = array_shift($result_vector); - if (is_array($dataValue2)) { - $dataValue2 = array_shift($dataValue2); - } - $value = [$key1 => $dataValue1, $key2 => $dataValue2]; - } - unset($value); - } - - return self::VLOOKUP($lookup_value, $lookup_vector, 2); + return Lookup::lookup($lookup_value, $lookup_vector, $result_vector); } /** diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php new file mode 100644 index 00000000..53c9c9d8 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php @@ -0,0 +1,97 @@ + '') { + if (strpos($sheetName, ' ') !== false || strpos($sheetName, '[') !== false) { + $sheetName = "'{$sheetName}'"; + } + $sheetName .= '!'; + } + + return $sheetName; + } + + private static function formatAsA1(int $row, int $column, int $relativity, string $sheetName): string + { + $rowRelative = $columnRelative = '$'; + if (($relativity == self::ADDRESS_COLUMN_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) { + $columnRelative = ''; + } + if (($relativity == self::ADDRESS_ROW_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) { + $rowRelative = ''; + } + $column = Coordinate::stringFromColumnIndex($column); + + return "{$sheetName}{$columnRelative}{$column}{$rowRelative}{$row}"; + } + + private static function formatAsR1C1(int $row, int $column, int $relativity, string $sheetName): string + { + if (($relativity == self::ADDRESS_COLUMN_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) { + $column = "[{$column}]"; + } + if (($relativity == self::ADDRESS_ROW_RELATIVE) || ($relativity == self::ADDRESS_RELATIVE)) { + $row = "[{$row}]"; + } + + return "{$sheetName}R{$row}C{$column}"; + } +} diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php b/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php new file mode 100644 index 00000000..559fe7d1 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php @@ -0,0 +1,86 @@ +getMessage(); + } + + $f = array_keys($lookupArray); + $firstRow = reset($f); + if ((!is_array($lookupArray[$firstRow])) || ($indexNumber > count($lookupArray))) { + return Functions::REF(); + } + + $firstkey = $f[0] - 1; + $returnColumn = $firstkey + $indexNumber; + $firstColumn = array_shift($f); + $rowNumber = self::hLookupSearch($lookupValue, $lookupArray, $firstColumn, $notExactMatch); + + if ($rowNumber !== null) { + // otherwise return the appropriate value + return $lookupArray[$returnColumn][$rowNumber]; + } + + return Functions::NA(); + } + + private static function hLookupSearch($lookupValue, $lookupArray, $column, $notExactMatch) + { + $lookupLower = StringHelper::strToLower($lookupValue); + + $rowNumber = null; + foreach ($lookupArray[$column] as $rowKey => $rowData) { + // break if we have passed possible keys + $bothNumeric = is_numeric($lookupValue) && is_numeric($rowData); + $bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData); + $cellDataLower = StringHelper::strToLower($rowData); + + if ( + $notExactMatch && + (($bothNumeric && $rowData > $lookupValue) || ($bothNotNumeric && $cellDataLower > $lookupLower)) + ) { + break; + } + + $rowNumber = self::checkMatch( + $bothNumeric, + $bothNotNumeric, + $notExactMatch, + $rowKey, + $cellDataLower, + $lookupLower, + $rowNumber + ); + } + + return $rowNumber; + } +} diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php b/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php new file mode 100644 index 00000000..9d75efb0 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php @@ -0,0 +1,105 @@ + 1) || (!$hasResultVector && $lookupRows === 2 && $lookupColumns !== 2)) { + $lookupVector = LookupRef::TRANSPOSE($lookupVector); + $lookupRows = self::rowCount($lookupVector); + $lookupColumns = self::columnCount($lookupVector); + } + + $resultVector = self::verifyResultVector($lookupVector, $resultVector); + + if ($lookupRows === 2 && !$hasResultVector) { + $resultVector = array_pop($lookupVector); + $lookupVector = array_shift($lookupVector); + } + + if ($lookupColumns !== 2) { + $lookupVector = self::verifyLookupValues($lookupVector, $resultVector); + } + + return VLookup::lookup($lookupValue, $lookupVector, 2); + } + + private static function verifyLookupValues(array $lookupVector, array $resultVector): array + { + foreach ($lookupVector as &$value) { + if (is_array($value)) { + $k = array_keys($value); + $key1 = $key2 = array_shift($k); + ++$key2; + $dataValue1 = $value[$key1]; + } else { + $key1 = 0; + $key2 = 1; + $dataValue1 = $value; + } + + $dataValue2 = array_shift($resultVector); + if (is_array($dataValue2)) { + $dataValue2 = array_shift($dataValue2); + } + $value = [$key1 => $dataValue1, $key2 => $dataValue2]; + } + unset($value); + + return $lookupVector; + } + + private static function verifyResultVector(array $lookupVector, $resultVector) + { + if ($resultVector === null) { + $resultVector = $lookupVector; + } + + $resultRows = self::rowCount($resultVector); + $resultColumns = self::columnCount($resultVector); + + // we correctly orient our results + if ($resultRows === 1 && $resultColumns > 1) { + $resultVector = LookupRef::TRANSPOSE($resultVector); + } + + return $resultVector; + } + + private static function rowCount(array $dataArray): int + { + return count($dataArray); + } + + private static function columnCount(array $dataArray): int + { + $rowKeys = array_keys($dataArray); + $row = array_shift($rowKeys); + + return count($dataArray[$row]); + } +} diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php b/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php new file mode 100644 index 00000000..80fc99ad --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php @@ -0,0 +1,48 @@ +getColumn()) : 1; + } + + if (is_array($cellAddress)) { + foreach ($cellAddress as $columnKey => $value) { + $columnKey = preg_replace('/[^a-z]/i', '', $columnKey); + + return (int) Coordinate::columnIndexFromString($columnKey); + } + } else { + [, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); + if (strpos($cellAddress, ':') !== false) { + [$startAddress, $endAddress] = explode(':', $cellAddress); + $startAddress = preg_replace('/[^a-z]/i', '', $startAddress); + $endAddress = preg_replace('/[^a-z]/i', '', $endAddress); + $returnValue = []; + do { + $returnValue[] = (int) Coordinate::columnIndexFromString($startAddress); + } while ($startAddress++ != $endAddress); + + return $returnValue; + } + $cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress); + + return (int) Coordinate::columnIndexFromString($cellAddress); + } + } + + /** + * COLUMNS. + * + * Returns the number of columns in an array or reference. + * + * Excel Function: + * =COLUMNS(cellAddress) + * + * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells + * for which you want the number of columns + * + * @return int|string The number of columns in cellAddress, or a string if arguments are invalid + */ + public static function COLUMNS($cellAddress = null) + { + if ($cellAddress === null || $cellAddress === '') { + return 1; + } elseif (!is_array($cellAddress)) { + return Functions::VALUE(); + } + + reset($cellAddress); + $isMatrix = (is_numeric(key($cellAddress))); + [$columns, $rows] = Calculation::getMatrixDimensions($cellAddress); + + if ($isMatrix) { + return $rows; + } + + return $columns; + } + + /** + * ROW. + * + * Returns the row number of the given cell reference + * If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference + * as a vertical array. + * If cell reference is omitted, and the function is being called through the calculation engine, + * then it is assumed to be the reference of the cell in which the ROW function appears; + * otherwise this function returns 1. + * + * Excel Function: + * =ROW([cellAddress]) + * + * @param null|array|string $cellAddress A reference to a range of cells for which you want the row numbers + * + * @return int|mixed[]|string + */ + public static function ROW($cellAddress = null, ?Cell $pCell = null) + { + if ($cellAddress === null || (!is_array($cellAddress) && trim($cellAddress) === '')) { + return ($pCell !== null) ? $pCell->getRow() : 1; + } + + if (is_array($cellAddress)) { + foreach ($cellAddress as $columnKey => $rowValue) { + foreach ($rowValue as $rowKey => $cellValue) { + return (int) preg_replace('/\D/', '', $rowKey); + } + } + } else { + [, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); + if (strpos($cellAddress, ':') !== false) { + [$startAddress, $endAddress] = explode(':', $cellAddress); + $startAddress = preg_replace('/\D/', '', $startAddress); + $endAddress = preg_replace('/\D/', '', $endAddress); + $returnValue = []; + do { + $returnValue[][] = (int) $startAddress; + } while ($startAddress++ != $endAddress); + + return $returnValue; + } + [$cellAddress] = explode(':', $cellAddress); + + return (int) preg_replace('/\D/', '', $cellAddress); + } + } + + /** + * ROWS. + * + * Returns the number of rows in an array or reference. + * + * Excel Function: + * =ROWS(cellAddress) + * + * @param null|array|string $cellAddress An array or array formula, or a reference to a range of cells + * for which you want the number of rows + * + * @return int|string The number of rows in cellAddress, or a string if arguments are invalid + */ + public static function ROWS($cellAddress = null) + { + if ($cellAddress === null || $cellAddress === '') { + return 1; + } elseif (!is_array($cellAddress)) { + return Functions::VALUE(); + } + + reset($cellAddress); + $isMatrix = (is_numeric(key($cellAddress))); + [$columns, $rows] = Calculation::getMatrixDimensions($cellAddress); + + if ($isMatrix) { + return $columns; + } + + return $rows; + } +} diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php b/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php new file mode 100644 index 00000000..f890e496 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php @@ -0,0 +1,105 @@ +getMessage(); + } + + $f = array_keys($lookupArray); + $firstRow = array_pop($f); + if ((!is_array($lookupArray[$firstRow])) || ($indexNumber > count($lookupArray[$firstRow]))) { + return Functions::REF(); + } + $columnKeys = array_keys($lookupArray[$firstRow]); + $returnColumn = $columnKeys[--$indexNumber]; + $firstColumn = array_shift($columnKeys); + + if (!$notExactMatch) { + uasort($lookupArray, ['self', 'vlookupSort']); + } + + $rowNumber = self::vLookupSearch($lookupValue, $lookupArray, $firstColumn, $notExactMatch); + + if ($rowNumber !== null) { + // return the appropriate value + return $lookupArray[$rowNumber][$returnColumn]; + } + + return Functions::NA(); + } + + private static function vlookupSort($a, $b) + { + reset($a); + $firstColumn = key($a); + $aLower = StringHelper::strToLower($a[$firstColumn]); + $bLower = StringHelper::strToLower($b[$firstColumn]); + + if ($aLower == $bLower) { + return 0; + } + + return ($aLower < $bLower) ? -1 : 1; + } + + private static function vLookupSearch($lookupValue, $lookupArray, $column, $notExactMatch) + { + $lookupLower = StringHelper::strToLower($lookupValue); + + $rowNumber = null; + foreach ($lookupArray as $rowKey => $rowData) { + $bothNumeric = is_numeric($lookupValue) && is_numeric($rowData[$column]); + $bothNotNumeric = !is_numeric($lookupValue) && !is_numeric($rowData[$column]); + $cellDataLower = StringHelper::strToLower($rowData[$column]); + + // break if we have passed possible keys + if ( + $notExactMatch && + (($bothNumeric && ($rowData[$column] > $lookupValue)) || + ($bothNotNumeric && ($cellDataLower > $lookupLower))) + ) { + break; + } + + $rowNumber = self::checkMatch( + $bothNumeric, + $bothNotNumeric, + $notExactMatch, + $rowKey, + $cellDataLower, + $lookupLower, + $rowNumber + ); + } + + return $rowNumber; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php new file mode 100644 index 00000000..17063edc --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php @@ -0,0 +1,31 @@ +getMockBuilder(Cell::class) + ->setMethods(['getColumn']) + ->disableOriginalConstructor() + ->getMock(); + $cell->method('getColumn') + ->willReturn('D'); + + $result = LookupRef::COLUMN(null, $cell); + self::assertSame(4, $result); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php index 9471e647..804b924d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\LookupRef; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef; +use PhpOffice\PhpSpreadsheet\Cell\Cell; use PHPUnit\Framework\TestCase; class RowTest extends TestCase @@ -17,8 +18,9 @@ class RowTest extends TestCase * @dataProvider providerROW * * @param mixed $expectedResult + * @param null|mixed $cellReference */ - public function testROW($expectedResult, string $cellReference): void + public function testROW($expectedResult, $cellReference = null): void { $result = LookupRef::ROW($cellReference); self::assertSame($expectedResult, $result); @@ -28,4 +30,17 @@ class RowTest extends TestCase { return require 'tests/data/Calculation/LookupRef/ROW.php'; } + + public function testROWwithNull(): void + { + $cell = $this->getMockBuilder(Cell::class) + ->setMethods(['getRow']) + ->disableOriginalConstructor() + ->getMock(); + $cell->method('getRow') + ->willReturn(3); + + $result = LookupRef::ROW(null, $cell); + self::assertSame(3, $result); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php new file mode 100644 index 00000000..1c75ab09 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php @@ -0,0 +1,32 @@ + 'B5', 'C' => 'C5', 'D' => 'D5'], + ], + [ + [2, 3, 4], + 'B2:D3', + ], + [ + [2, 3, 4], + 'Sheet1!B2:D2', + ], + [ + [2, 3, 4], + '"WorkSheet #1"!B2:D2', + ], ]; diff --git a/tests/data/Calculation/LookupRef/HLOOKUP.php b/tests/data/Calculation/LookupRef/HLOOKUP.php index b880f247..d2a8a446 100644 --- a/tests/data/Calculation/LookupRef/HLOOKUP.php +++ b/tests/data/Calculation/LookupRef/HLOOKUP.php @@ -308,4 +308,24 @@ return [ 2, false, ], + [ + '#VALUE!', + 'B', + [ + ['Selection column', 'C', 'B', 'A'], + ['Value to retrieve', 3, 2, 1], + ], + 'Nan', + false, + ], + [ + '#REF!', + 'B', + [ + 'Selection column', + 'Value to retrieve', + ], + 2, + false, + ], ]; diff --git a/tests/data/Calculation/LookupRef/LOOKUP.php b/tests/data/Calculation/LookupRef/LOOKUP.php index ab322d57..9c7d96eb 100644 --- a/tests/data/Calculation/LookupRef/LOOKUP.php +++ b/tests/data/Calculation/LookupRef/LOOKUP.php @@ -1,7 +1,6 @@ Date: Wed, 10 Mar 2021 12:23:08 -0800 Subject: [PATCH 101/187] Fix for Issue #1887 - Lose Track of Selected Cells After Save (#1908) * Fix for Issue #1887 - Lose Track of Selected Cells After Save Issue #1887 reports that selected cells are lost after saving Xlsx. Testing indicates that this applies to the object in memory, though not to the saved spreadsheet. Xlsx writer tries to save calculated values for cells which contain formulas. Calculation::_calculateFormulaValue issues a getStyle call merely to retrieve the quotePrefix property, which, if set, indicates that the cell does not contain a formula even though it looks like one. A side-effect of calls to getStyle is that selectedCell is updated. That is clearly accidental, and highly undesirable, in this case. Code is changed to save selectedCell before getStyle call and restore it afterwards. The problem was reported only for Xlsx save. To be on the safe side, test is made for output formats of Xlsx, Xls, Ods, Html (which basically includes Pdf), and Csv. For all of those, the object in memory is tested after the save. For Xlsx and Xls, the saved file is also tested. It does not make sense to test the saved file for Csv and Html. It does make sense to test it for Ods, but the necessary support is not yet present in either the Ods Reader or Ods Writer - a project for another day. * Move Logic Out of Calculation, Add Support for Ods ActiveSheet and SelectedCells Mark Baker thought logic belonged in Worksheet, not Calculation. I couldn't get it to work in Worksheet, but doing it in Cell works, and that has already been used to preserve ActiveSheet over call to getCalculatedValue, so this just extends that idea to SelectedCells. Original tests could not completely support Ods because of a lack of support for ActiveSheet and SelectedCells in Ods Reader and Writer. There's a lot missing in Ods support, but a journey of 1000 miles ... Those two particular concepts are now supported for Ods. --- src/PhpSpreadsheet/Cell/Cell.php | 2 + src/PhpSpreadsheet/Reader/Ods.php | 72 +++++++++++++++++ src/PhpSpreadsheet/Writer/Ods/Settings.php | 51 ++++++++++-- .../Calculation/CalculationTest.php | 9 +++ .../Reader/Ods/OdsTest.php | 14 ++++ .../Writer/RetainSelectedCellsTest.php | 77 +++++++++++++++++++ 6 files changed, 219 insertions(+), 6 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index 5dee411b..f971a3c8 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -252,9 +252,11 @@ class Cell if ($this->dataType == DataType::TYPE_FORMULA) { try { $index = $this->getWorksheet()->getParent()->getActiveSheetIndex(); + $selected = $this->getWorksheet()->getSelectedCells(); $result = Calculation::getInstance( $this->getWorksheet()->getParent() )->calculateCellValue($this, $resetLog); + $this->getWorksheet()->setSelectedCells($selected); $this->getWorksheet()->getParent()->setActiveSheetIndex($index); // We don't yet handle array returns if (is_array($result)) { diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index 4ceac653..59d934be 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -23,6 +23,7 @@ use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use Throwable; use XMLReader; use ZipArchive; @@ -646,10 +647,81 @@ class Ods extends BaseReader $this->readDefinedExpressions($spreadsheet, $workbookData, $tableNs); } $spreadsheet->setActiveSheetIndex(0); + + if ($zip->locateName('settings.xml') !== false) { + $this->processSettings($zip, $spreadsheet); + } // Return return $spreadsheet; } + private function processSettings(ZipArchive $zip, Spreadsheet $spreadsheet): void + { + $dom = new DOMDocument('1.01', 'UTF-8'); + $dom->loadXML( + $this->securityScanner->scan($zip->getFromName('settings.xml')), + Settings::getLibXmlLoaderOptions() + ); + //$xlinkNs = $dom->lookupNamespaceUri('xlink'); + $configNs = $dom->lookupNamespaceUri('config'); + //$oooNs = $dom->lookupNamespaceUri('ooo'); + $officeNs = $dom->lookupNamespaceUri('office'); + $settings = $dom->getElementsByTagNameNS($officeNs, 'settings') + ->item(0); + $this->lookForActiveSheet($settings, $spreadsheet, $configNs); + $this->lookForSelectedCells($settings, $spreadsheet, $configNs); + } + + private function lookForActiveSheet(DOMNode $settings, Spreadsheet $spreadsheet, string $configNs): void + { + foreach ($settings->getElementsByTagNameNS($configNs, 'config-item') as $t) { + if ($t->getAttributeNs($configNs, 'name') === 'ActiveTable') { + try { + $spreadsheet->setActiveSheetIndexByName($t->nodeValue); + } catch (Throwable $e) { + // do nothing + } + + break; + } + } + } + + private function lookForSelectedCells(DOMNode $settings, Spreadsheet $spreadsheet, string $configNs): void + { + foreach ($settings->getElementsByTagNameNS($configNs, 'config-item-map-named') as $t) { + if ($t->getAttributeNs($configNs, 'name') === 'Tables') { + foreach ($t->getElementsByTagNameNS($configNs, 'config-item-map-entry') as $ws) { + $setRow = $setCol = ''; + $wsname = $ws->getAttributeNs($configNs, 'name'); + foreach ($ws->getElementsByTagNameNS($configNs, 'config-item') as $configItem) { + $attrName = $configItem->getAttributeNs($configNs, 'name'); + if ($attrName === 'CursorPositionX') { + $setCol = $configItem->nodeValue; + } + if ($attrName === 'CursorPositionY') { + $setRow = $configItem->nodeValue; + } + } + $this->setSelected($spreadsheet, $wsname, $setCol, $setRow); + } + + break; + } + } + } + + private function setSelected(Spreadsheet $spreadsheet, string $wsname, string $setCol, string $setRow): void + { + if (is_numeric($setCol) && is_numeric($setRow)) { + try { + $spreadsheet->getSheetByName($wsname)->setSelectedCellByColumnAndRow($setCol + 1, $setRow + 1); + } catch (Throwable $e) { + // do nothing + } + } + } + /** * Recursively scan element. * diff --git a/src/PhpSpreadsheet/Writer/Ods/Settings.php b/src/PhpSpreadsheet/Writer/Ods/Settings.php index d458e8c2..301daf03 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Settings.php +++ b/src/PhpSpreadsheet/Writer/Ods/Settings.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; +use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -16,7 +17,6 @@ class Settings extends WriterPart */ public function write(?Spreadsheet $spreadsheet = null) { - $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); } else { @@ -39,13 +39,52 @@ class Settings extends WriterPart $objWriter->writeAttribute('config:name', 'ooo:view-settings'); $objWriter->startElement('config:config-item-map-indexed'); $objWriter->writeAttribute('config:name', 'Views'); - $objWriter->endElement(); - $objWriter->endElement(); + $objWriter->startElement('config:config-item-map-entry'); + $spreadsheet = $spreadsheet ?? $this->getParentWriter()->getSpreadsheet(); + + $objWriter->startElement('config:config-item'); + $objWriter->writeAttribute('config:name', 'ViewId'); + $objWriter->writeAttribute('config:type', 'string'); + $objWriter->text('view1'); + $objWriter->endElement(); // ViewId + $objWriter->startElement('config:config-item-map-named'); + $objWriter->writeAttribute('config:name', 'Tables'); + foreach ($spreadsheet->getWorksheetIterator() as $ws) { + $objWriter->startElement('config:config-item-map-entry'); + $objWriter->writeAttribute('config:name', $ws->getTitle()); + $selected = $ws->getSelectedCells(); + if (preg_match('/^([a-z]+)([0-9]+)/i', $selected, $matches) === 1) { + $colSel = Coordinate::columnIndexFromString($matches[1]) - 1; + $rowSel = (int) $matches[2] - 1; + $objWriter->startElement('config:config-item'); + $objWriter->writeAttribute('config:name', 'CursorPositionX'); + $objWriter->writeAttribute('config:type', 'int'); + $objWriter->text($colSel); + $objWriter->endElement(); + $objWriter->startElement('config:config-item'); + $objWriter->writeAttribute('config:name', 'CursorPositionY'); + $objWriter->writeAttribute('config:type', 'int'); + $objWriter->text($rowSel); + $objWriter->endElement(); + } + $objWriter->endElement(); // config:config-item-map-entry + } + $objWriter->endElement(); // config:config-item-map-named + $wstitle = $spreadsheet->getActiveSheet()->getTitle(); + $objWriter->startElement('config:config-item'); + $objWriter->writeAttribute('config:name', 'ActiveTable'); + $objWriter->writeAttribute('config:type', 'string'); + $objWriter->text($wstitle); + $objWriter->endElement(); // config:config-item ActiveTable + + $objWriter->endElement(); // config:config-item-map-entry + $objWriter->endElement(); // config:config-item-map-indexed Views + $objWriter->endElement(); // config:config-item-set ooo:view-settings $objWriter->startElement('config:config-item-set'); $objWriter->writeAttribute('config:name', 'ooo:configuration-settings'); - $objWriter->endElement(); - $objWriter->endElement(); - $objWriter->endElement(); + $objWriter->endElement(); // config:config-item-set ooo:configuration-settings + $objWriter->endElement(); // office:settings + $objWriter->endElement(); // office:document-settings return $objWriter->getData(); } diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php index 8e339207..337501f9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; @@ -159,6 +160,14 @@ class CalculationTest extends TestCase $cell->getStyle()->setQuotePrefix(true); self::assertEquals("=cmd|'/C calc'!A0", $cell->getCalculatedValue()); + + $cell2 = $workSheet->getCell('A2'); + $cell2->setValueExplicit('ABC', DataType::TYPE_FORMULA); + self::assertEquals('ABC', $cell2->getCalculatedValue()); + + $cell3 = $workSheet->getCell('A3'); + $cell3->setValueExplicit('=', DataType::TYPE_FORMULA); + self::assertEquals('', $cell3->getCalculatedValue()); } public function testCellWithDdeExpresion(): void diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php index 0160f68d..2cc5377a 100644 --- a/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php @@ -101,6 +101,20 @@ class OdsTest extends TestCase self::assertEquals('Sheet1', $spreadsheet->getSheet(0)->getTitle()); } + public function testLoadOneWorksheetNotActive(): void + { + $filename = 'tests/data/Reader/Ods/data.ods'; + + // Load into this instance + $reader = new Ods(); + $reader->setLoadSheetsOnly(['Second Sheet']); + $spreadsheet = $reader->load($filename); + + self::assertEquals(1, $spreadsheet->getSheetCount()); + + self::assertEquals('Second Sheet', $spreadsheet->getSheet(0)->getTitle()); + } + public function testLoadBadFile(): void { $this->expectException(ReaderException::class); diff --git a/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php b/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php new file mode 100644 index 00000000..c1a57eb5 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php @@ -0,0 +1,77 @@ +getActiveSheet(); + $sheet->setCellValue('A1', '=SIN(1)') + ->setCellValue('A2', '=SIN(2)') + ->setCellValue('A3', '=SIN(3)') + ->setCellValue('B1', '=SIN(4)') + ->setCellValue('B2', '=SIN(5)') + ->setCellValue('B3', '=SIN(6)') + ->setCellValue('C1', '=SIN(7)') + ->setCellValue('C2', '=SIN(8)') + ->setCellValue('C3', '=SIN(9)'); + $sheet->setSelectedCell('A3'); + $sheet = $spreadsheet->createSheet(); + $sheet->setCellValue('A1', '=SIN(1)') + ->setCellValue('A2', '=SIN(2)') + ->setCellValue('A3', '=SIN(3)') + ->setCellValue('B1', '=SIN(4)') + ->setCellValue('B2', '=SIN(5)') + ->setCellValue('B3', '=SIN(6)') + ->setCellValue('C1', '=SIN(7)') + ->setCellValue('C2', '=SIN(8)') + ->setCellValue('C3', '=SIN(9)'); + $sheet->setSelectedCell('B1'); + $sheet = $spreadsheet->createSheet(); + $sheet->setCellValue('A1', '=SIN(1)') + ->setCellValue('A2', '=SIN(2)') + ->setCellValue('A3', '=SIN(3)') + ->setCellValue('B1', '=SIN(4)') + ->setCellValue('B2', '=SIN(5)') + ->setCellValue('B3', '=SIN(6)') + ->setCellValue('C1', '=SIN(7)') + ->setCellValue('C2', '=SIN(8)') + ->setCellValue('C3', '=SIN(9)'); + $sheet->setSelectedCell('C2'); + $spreadsheet->setActiveSheetIndex(1); + + $reloaded = $this->writeAndReload($spreadsheet, $format); + self::assertEquals('A3', $spreadsheet->getSheet(0)->getSelectedCells()); + self::assertEquals('B1', $spreadsheet->getSheet(1)->getSelectedCells()); + self::assertEquals('C2', $spreadsheet->getSheet(2)->getSelectedCells()); + self::assertEquals(1, $spreadsheet->getActiveSheetIndex()); + // SelectedCells and ActiveSheet don't make sense for Html, Csv. + if ($format === 'Xlsx' || $format === 'Xls' || $format === 'Ods') { + self::assertEquals('A3', $reloaded->getSheet(0)->getSelectedCells()); + self::assertEquals('B1', $reloaded->getSheet(1)->getSelectedCells()); + self::assertEquals('C2', $reloaded->getSheet(2)->getSelectedCells()); + self::assertEquals(1, $reloaded->getActiveSheetIndex()); + } + } +} From 4717741dc24b2cc294568169316984c8377c728e Mon Sep 17 00:00:00 2001 From: MarkBaker Date: Wed, 10 Mar 2021 21:30:39 +0100 Subject: [PATCH 102/187] Update ChangeLog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2474e26d..b5e273f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Nothing. +- Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) ### Changed @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fix for [Issue #1887](https://github.com/PHPOffice/PhpSpreadsheet/issues/1887) - Lose Track of Selected Cells After Save - Fixed issue with Xlsx@listWorksheetInfo not returning any data - Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640) From 499ce61cf7aa496e504e0ab9aa185d602843f572 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 10 Mar 2021 22:38:41 +0100 Subject: [PATCH 103/187] Unhappy path tests for FORMULATEXT() Function (#1915) * Unhappy path tests --- tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php b/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php index 04dc0a32..6d603722 100644 --- a/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php @@ -73,4 +73,10 @@ class LookupRefTest extends TestCase { return require 'tests/data/Calculation/LookupRef/FORMULATEXT.php'; } + + public function testFormulaTextWithoutCell(): void + { + $result = LookupRef::FORMULATEXT('A1'); + self::assertEquals(Functions::REF(), $result); + } } From 2259de578b5717d0b7e3d59ba9de227d6e80c7b6 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Thu, 11 Mar 2021 22:34:47 +0100 Subject: [PATCH 104/187] Lookup ref further tests and examples (#1918) * Extract LookupRef\INDEX() into index() method of LookupRef\Matrix class Additional tests * Bugfix for returning a column using INDEX() * Some improvements to ROW() and COLUMN() * Simplify some of the INDEX() logic, eliminating redundant code --- samples/Calculations/LookupRef/ADDRESS.php | 22 ++++++ samples/Calculations/LookupRef/COLUMN.php | 23 ++++++ samples/Calculations/LookupRef/COLUMNS.php | 21 ++++++ samples/Calculations/LookupRef/INDEX.php | 39 ++++++++++ samples/Calculations/LookupRef/ROW.php | 20 +++++ samples/Calculations/LookupRef/ROWS.php | 20 +++++ src/PhpSpreadsheet/Calculation/LookupRef.php | 60 +++------------ .../Calculation/LookupRef/Matrix.php | 71 ++++++++++++++++++ .../LookupRef/RowColumnInformation.php | 73 ++++++++++--------- .../Functions/LookupRef/IndexTest.php | 1 + tests/data/Calculation/LookupRef/INDEX.php | 72 +++++++++++++++++- tests/data/Calculation/LookupRef/ROW.php | 7 ++ 12 files changed, 343 insertions(+), 86 deletions(-) create mode 100644 samples/Calculations/LookupRef/ADDRESS.php create mode 100644 samples/Calculations/LookupRef/COLUMN.php create mode 100644 samples/Calculations/LookupRef/COLUMNS.php create mode 100644 samples/Calculations/LookupRef/INDEX.php create mode 100644 samples/Calculations/LookupRef/ROW.php create mode 100644 samples/Calculations/LookupRef/ROWS.php diff --git a/samples/Calculations/LookupRef/ADDRESS.php b/samples/Calculations/LookupRef/ADDRESS.php new file mode 100644 index 00000000..2377541d --- /dev/null +++ b/samples/Calculations/LookupRef/ADDRESS.php @@ -0,0 +1,22 @@ +log('Returns a text reference to a single cell in a worksheet.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$worksheet->getCell('A1')->setValue('=ADDRESS(2,3)'); +$worksheet->getCell('A2')->setValue('=ADDRESS(2,3,2)'); +$worksheet->getCell('A3')->setValue('=ADDRESS(2,3,2,FALSE)'); +$worksheet->getCell('A4')->setValue('=ADDRESS(2,3,1,FALSE,"[Book1]Sheet1")'); +$worksheet->getCell('A5')->setValue('=ADDRESS(2,3,1,FALSE,"EXCEL SHEET")'); + +for ($row = 1; $row <= 5; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/samples/Calculations/LookupRef/COLUMN.php b/samples/Calculations/LookupRef/COLUMN.php new file mode 100644 index 00000000..e9e58466 --- /dev/null +++ b/samples/Calculations/LookupRef/COLUMN.php @@ -0,0 +1,23 @@ +log('Returns the column index of a cell.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$worksheet->getCell('A1')->setValue('=COLUMN(C13)'); +$worksheet->getCell('A2')->setValue('=COLUMN(E13:G15)'); +$worksheet->getCell('F1')->setValue('=COLUMN()'); + +for ($row = 1; $row <= 2; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} + +$cell = $worksheet->getCell('F1'); +$helper->log("F1: {$cell->getValue()} => {$cell->getCalculatedValue()}"); diff --git a/samples/Calculations/LookupRef/COLUMNS.php b/samples/Calculations/LookupRef/COLUMNS.php new file mode 100644 index 00000000..4d7f8d10 --- /dev/null +++ b/samples/Calculations/LookupRef/COLUMNS.php @@ -0,0 +1,21 @@ +log('Returns the number of columns in an array or reference.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$worksheet->getCell('A1')->setValue('=COLUMNS(C1:G4)'); +$worksheet->getCell('A2')->setValue('=COLUMNS({1,2,3;4,5,6})'); +$worksheet->getCell('A3')->setValue('=ROWS(C1:E4 D3:G5)'); +$worksheet->getCell('A4')->setValue('=COLUMNS(1:1)'); + +for ($row = 1; $row <= 4; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/samples/Calculations/LookupRef/INDEX.php b/samples/Calculations/LookupRef/INDEX.php new file mode 100644 index 00000000..9ef0b945 --- /dev/null +++ b/samples/Calculations/LookupRef/INDEX.php @@ -0,0 +1,39 @@ +log('Returns the row index of a cell.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$data1 = [ + ['Apples', 'Lemons'], + ['Bananas', 'Pears'], +]; + +$data2 = [ + [4, 6], + [5, 3], + [6, 9], + [7, 5], + [8, 3], +]; + +$worksheet->fromArray($data1, null, 'A1'); +$worksheet->fromArray($data2, null, 'C1'); + +$worksheet->getCell('A11')->setValue('=INDEX(A1:B2, 2, 2)'); +$worksheet->getCell('A12')->setValue('=INDEX(A1:B2, 2, 1)'); +$worksheet->getCell('A13')->setValue('=INDEX({1,2;3,4}, 0, 2)'); +$worksheet->getCell('A14')->setValue('=INDEX(C1:C5, 5)'); +$worksheet->getCell('A15')->setValue('=INDEX(C1:D5, 5, 2)'); +$worksheet->getCell('A16')->setValue('=SUM(INDEX(C1:D5, 5, 0))'); + +for ($row = 11; $row <= 16; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/samples/Calculations/LookupRef/ROW.php b/samples/Calculations/LookupRef/ROW.php new file mode 100644 index 00000000..560639a5 --- /dev/null +++ b/samples/Calculations/LookupRef/ROW.php @@ -0,0 +1,20 @@ +log('Returns the row index of a cell.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$worksheet->getCell('A1')->setValue('=ROW(C13)'); +$worksheet->getCell('A2')->setValue('=ROW(E19:G21)'); +$worksheet->getCell('A3')->setValue('=ROW()'); + +for ($row = 1; $row <= 3; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/samples/Calculations/LookupRef/ROWS.php b/samples/Calculations/LookupRef/ROWS.php new file mode 100644 index 00000000..3cdf085b --- /dev/null +++ b/samples/Calculations/LookupRef/ROWS.php @@ -0,0 +1,20 @@ +log('Returns the row index of a cell.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$worksheet->getCell('A1')->setValue('=ROWS(C1:E4)'); +$worksheet->getCell('A2')->setValue('=ROWS({1,2,3;4,5,6})'); +$worksheet->getCell('A3')->setValue('=ROWS(C1:E4 D3:G5)'); + +for ($row = 1; $row <= 3; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index 39823a20..f1a147f1 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -529,59 +529,21 @@ class LookupRef * Excel Function: * =INDEX(range_array, row_num, [column_num]) * - * @param mixed $arrayValues A range of cells or an array constant - * @param mixed $rowNum The row in array from which to return a value. If row_num is omitted, column_num is required. - * @param mixed $columnNum The column in array from which to return a value. If column_num is omitted, row_num is required. + * @Deprecated 1.18.0 + * + * @see Use the index() method in the LookupRef\Matrix class instead + * + * @param mixed $rowNum The row in the array or range from which to return a value. + * If row_num is omitted, column_num is required. + * @param mixed $columnNum The column in the array or range from which to return a value. + * If column_num is omitted, row_num is required. + * @param mixed $matrix * * @return mixed the value of a specified cell or array of cells */ - public static function INDEX($arrayValues, $rowNum = 0, $columnNum = 0) + public static function INDEX($matrix, $rowNum = 0, $columnNum = 0) { - $rowNum = Functions::flattenSingleValue($rowNum); - $columnNum = Functions::flattenSingleValue($columnNum); - - if (($rowNum < 0) || ($columnNum < 0)) { - return Functions::VALUE(); - } - - if (!is_array($arrayValues) || ($rowNum > count($arrayValues))) { - return Functions::REF(); - } - - $rowKeys = array_keys($arrayValues); - $columnKeys = @array_keys($arrayValues[$rowKeys[0]]); - - if ($columnNum > count($columnKeys)) { - return Functions::VALUE(); - } elseif ($columnNum == 0) { - if ($rowNum == 0) { - return $arrayValues; - } - $rowNum = $rowKeys[--$rowNum]; - $returnArray = []; - foreach ($arrayValues as $arrayColumn) { - if (is_array($arrayColumn)) { - if (isset($arrayColumn[$rowNum])) { - $returnArray[] = $arrayColumn[$rowNum]; - } else { - return [$rowNum => $arrayValues[$rowNum]]; - } - } else { - return $arrayValues[$rowNum]; - } - } - - return $returnArray; - } - $columnNum = $columnKeys[--$columnNum]; - if ($rowNum > count($rowKeys)) { - return Functions::VALUE(); - } elseif ($rowNum == 0) { - return $arrayValues[$columnNum]; - } - $rowNum = $rowKeys[--$rowNum]; - - return $arrayValues[$rowNum][$columnNum]; + return Matrix::index($matrix, $rowNum, $columnNum); } /** diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php index 99fd6e6e..8859a287 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\LookupRef; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; + class Matrix { /** @@ -30,4 +32,73 @@ class Matrix return $returnMatrix; } + + /** + * INDEX. + * + * Uses an index to choose a value from a reference or array + * + * Excel Function: + * =INDEX(range_array, row_num, [column_num]) + * + * @param mixed $matrix A range of cells or an array constant + * @param mixed $rowNum The row in the array or range from which to return a value. + * If row_num is omitted, column_num is required. + * @param mixed $columnNum The column in the array or range from which to return a value. + * If column_num is omitted, row_num is required. + * + * @return mixed the value of a specified cell or array of cells + */ + public static function index($matrix, $rowNum = 0, $columnNum = 0) + { + $rowNum = Functions::flattenSingleValue($rowNum); + $columnNum = Functions::flattenSingleValue($columnNum); + + if (!is_numeric($rowNum) || !is_numeric($columnNum) || ($rowNum < 0) || ($columnNum < 0)) { + return Functions::VALUE(); + } + + if (!is_array($matrix) || ($rowNum > count($matrix))) { + return Functions::REF(); + } + + $rowKeys = array_keys($matrix); + $columnKeys = @array_keys($matrix[$rowKeys[0]]); + + if ($columnNum > count($columnKeys)) { + return Functions::REF(); + } + + if ($columnNum == 0) { + return self::extractRowValue($matrix, $rowKeys, $rowNum); + } + + $columnNum = $columnKeys[--$columnNum]; + if ($rowNum == 0) { + return array_map( + function ($value) { + return [$value]; + }, + array_column($matrix, $columnNum) + ); + } + $rowNum = $rowKeys[--$rowNum]; + + return $matrix[$rowNum][$columnNum]; + } + + private static function extractRowValue(array $matrix, array $rowKeys, int $rowNum) + { + if ($rowNum == 0) { + return $matrix; + } + + $rowNum = $rowKeys[--$rowNum]; + $row = $matrix[$rowNum]; + if (is_array($row)) { + return [$rowNum => $row]; + } + + return $row; + } } diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php b/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php index 0cce806a..19d0d5ff 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php @@ -39,23 +39,23 @@ class RowColumnInformation return (int) Coordinate::columnIndexFromString($columnKey); } - } else { - [, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - if (strpos($cellAddress, ':') !== false) { - [$startAddress, $endAddress] = explode(':', $cellAddress); - $startAddress = preg_replace('/[^a-z]/i', '', $startAddress); - $endAddress = preg_replace('/[^a-z]/i', '', $endAddress); - $returnValue = []; - do { - $returnValue[] = (int) Coordinate::columnIndexFromString($startAddress); - } while ($startAddress++ != $endAddress); - - return $returnValue; - } - $cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress); - - return (int) Coordinate::columnIndexFromString($cellAddress); } + + [, $cellAddress] = Worksheet::extractSheetTitle((string) $cellAddress, true); + if (strpos($cellAddress, ':') !== false) { + [$startAddress, $endAddress] = explode(':', $cellAddress); + $startAddress = preg_replace('/[^a-z]/i', '', $startAddress); + $endAddress = preg_replace('/[^a-z]/i', '', $endAddress); + + return range( + (int) Coordinate::columnIndexFromString($startAddress), + (int) Coordinate::columnIndexFromString($endAddress) + ); + } + + $cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress); + + return (int) Coordinate::columnIndexFromString($cellAddress); } /** @@ -73,7 +73,7 @@ class RowColumnInformation */ public static function COLUMNS($cellAddress = null) { - if ($cellAddress === null || $cellAddress === '') { + if ($cellAddress === null || (is_string($cellAddress) && trim($cellAddress) === '')) { return 1; } elseif (!is_array($cellAddress)) { return Functions::VALUE(); @@ -114,28 +114,29 @@ class RowColumnInformation } if (is_array($cellAddress)) { - foreach ($cellAddress as $columnKey => $rowValue) { - foreach ($rowValue as $rowKey => $cellValue) { + foreach ($cellAddress as $rowKey => $rowValue) { + foreach ($rowValue as $columnKey => $cellValue) { return (int) preg_replace('/\D/', '', $rowKey); } } - } else { - [, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - if (strpos($cellAddress, ':') !== false) { - [$startAddress, $endAddress] = explode(':', $cellAddress); - $startAddress = preg_replace('/\D/', '', $startAddress); - $endAddress = preg_replace('/\D/', '', $endAddress); - $returnValue = []; - do { - $returnValue[][] = (int) $startAddress; - } while ($startAddress++ != $endAddress); - - return $returnValue; - } - [$cellAddress] = explode(':', $cellAddress); - - return (int) preg_replace('/\D/', '', $cellAddress); } + + [, $cellAddress] = Worksheet::extractSheetTitle((string) $cellAddress, true); + if (strpos($cellAddress, ':') !== false) { + [$startAddress, $endAddress] = explode(':', $cellAddress); + $startAddress = preg_replace('/\D/', '', $startAddress); + $endAddress = preg_replace('/\D/', '', $endAddress); + + return array_map( + function ($value) { + return [$value]; + }, + range($startAddress, $endAddress) + ); + } + [$cellAddress] = explode(':', $cellAddress); + + return (int) preg_replace('/\D/', '', $cellAddress); } /** @@ -153,7 +154,7 @@ class RowColumnInformation */ public static function ROWS($cellAddress = null) { - if ($cellAddress === null || $cellAddress === '') { + if ($cellAddress === null || (is_string($cellAddress) && trim($cellAddress) === '')) { return 1; } elseif (!is_array($cellAddress)) { return Functions::VALUE(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php index 8ff66931..c84a504d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php @@ -21,6 +21,7 @@ class IndexTest extends TestCase public function testINDEX($expectedResult, ...$args): void { $result = LookupRef::INDEX(...$args); +// var_dump($result); self::assertEquals($expectedResult, $result); } diff --git a/tests/data/Calculation/LookupRef/INDEX.php b/tests/data/Calculation/LookupRef/INDEX.php index 55206270..157794ab 100644 --- a/tests/data/Calculation/LookupRef/INDEX.php +++ b/tests/data/Calculation/LookupRef/INDEX.php @@ -54,7 +54,7 @@ return [ -1, ], [ - '#VALUE!', // Expected + '#REF!', // Expected // Input [ '20' => ['R' => 1, 'S' => 3], @@ -63,6 +63,16 @@ return [ 2, 10, ], + [ + '#REF!', // Expected + // Input + [ + '20' => ['R' => 1, 'S' => 3], + '21' => ['R' => 2, 'S' => 4], + ], + 10, + 2, + ], [ 4, // Expected // Input @@ -87,4 +97,64 @@ return [ '21' => ['R' => 2], ], ], + [ + 'Pears', + [ + ['Apples', 'Lemons'], + ['Bananas', 'Pears'], + ], + 2, + 2, + ], + [ + 'Bananas', + [ + ['Apples', 'Lemons'], + ['Bananas', 'Pears'], + ], + 2, + 1, + ], + [ + 3, + [ + [4, 6], + [5, 3], + [6, 9], + [7, 5], + [8, 3], + ], + 5, + 2, + ], + [ + [4 => [8, 3]], + [ + [4, 6], + [5, 3], + [6, 9], + [7, 5], + [8, 3], + ], + 5, + 0, + ], + [ + [ + [6], + [3], + [9], + [5], + [3], + ], + [ + [4, 6], + [5, 3], + [6, 9], + [7, 5], + [8, 3], + ], + 0, + 2, + ], ]; diff --git a/tests/data/Calculation/LookupRef/ROW.php b/tests/data/Calculation/LookupRef/ROW.php index 89566011..62545c76 100644 --- a/tests/data/Calculation/LookupRef/ROW.php +++ b/tests/data/Calculation/LookupRef/ROW.php @@ -17,6 +17,13 @@ return [ [[10], [11], [12]], 'C10:D12', ], + [ + 4, + [ + 4 => ['B' => 'B5', 'C' => 'C5', 'D' => 'D5'], + 5 => ['B' => 'B5', 'C' => 'C5', 'D' => 'D5'], + ], + ], [ [[10], [11], [12]], 'Sheet1!C10:C12', From baacc83995852934afd1417e97b55b19a54519cd Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 12 Mar 2021 18:23:15 +0100 Subject: [PATCH 105/187] Replace manual wildcard logic in MATCH() function with the new WildcardMatch methods (#1919) * Replace manual wildcard logic in MATCH() function with the new WildcardMatch methods * Additional unit tests * Refactor input validations * Refactor actual search logic into dedicated methods * Eliminate redundant code --- .../Calculation/Calculation.php | 2 +- src/PhpSpreadsheet/Calculation/LookupRef.php | 141 +------------ .../Calculation/LookupRef/ExcelMatch.php | 198 ++++++++++++++++++ tests/data/Calculation/LookupRef/MATCH.php | 84 +++++++- 4 files changed, 279 insertions(+), 146 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 3adcf243..80b6d47b 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1616,7 +1616,7 @@ class Calculation ], 'MATCH' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'MATCH'], + 'functionCall' => [LookupRef\ExcelMatch::class, 'MATCH'], 'argumentCount' => '2,3', ], 'MAX' => [ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index f1a147f1..d2cc4f94 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -10,7 +10,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\RowColumnInformation; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\VLookup; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; -use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; class LookupRef @@ -380,145 +379,7 @@ class LookupRef */ public static function MATCH($lookupValue, $lookupArray, $matchType = 1) { - $lookupArray = Functions::flattenArray($lookupArray); - $lookupValue = Functions::flattenSingleValue($lookupValue); - $matchType = ($matchType === null) ? 1 : (int) Functions::flattenSingleValue($matchType); - - // MATCH is not case sensitive, so we convert lookup value to be lower cased in case it's string type. - if (is_string($lookupValue)) { - $lookupValue = StringHelper::strToLower($lookupValue); - } - - // Lookup_value type has to be number, text, or logical values - if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) { - return Functions::NA(); - } - - // Match_type is 0, 1 or -1 - if (($matchType !== 0) && ($matchType !== -1) && ($matchType !== 1)) { - return Functions::NA(); - } - - // Lookup_array should not be empty - $lookupArraySize = count($lookupArray); - if ($lookupArraySize <= 0) { - return Functions::NA(); - } - - if ($matchType == 1) { - // If match_type is 1 the list has to be processed from last to first - - $lookupArray = array_reverse($lookupArray); - $keySet = array_reverse(array_keys($lookupArray)); - } - - // Lookup_array should contain only number, text, or logical values, or empty (null) cells - foreach ($lookupArray as $i => $lookupArrayValue) { - // check the type of the value - if ( - (!is_numeric($lookupArrayValue)) && (!is_string($lookupArrayValue)) && - (!is_bool($lookupArrayValue)) && ($lookupArrayValue !== null) - ) { - return Functions::NA(); - } - // Convert strings to lowercase for case-insensitive testing - if (is_string($lookupArrayValue)) { - $lookupArray[$i] = StringHelper::strToLower($lookupArrayValue); - } - if (($lookupArrayValue === null) && (($matchType == 1) || ($matchType == -1))) { - unset($lookupArray[$i]); - } - } - - // ** - // find the match - // ** - - if ($matchType === 0 || $matchType === 1) { - foreach ($lookupArray as $i => $lookupArrayValue) { - $typeMatch = ((gettype($lookupValue) === gettype($lookupArrayValue)) || (is_numeric($lookupValue) && is_numeric($lookupArrayValue))); - $exactTypeMatch = $typeMatch && $lookupArrayValue === $lookupValue; - $nonOnlyNumericExactMatch = !$typeMatch && $lookupArrayValue === $lookupValue; - $exactMatch = $exactTypeMatch || $nonOnlyNumericExactMatch; - - if ($matchType === 0) { - if ($typeMatch && is_string($lookupValue) && (bool) preg_match('/([\?\*])/', $lookupValue)) { - $splitString = $lookupValue; - $chars = array_map(function ($i) use ($splitString) { - return mb_substr($splitString, $i, 1); - }, range(0, mb_strlen($splitString) - 1)); - - $length = count($chars); - $pattern = '/^'; - for ($j = 0; $j < $length; ++$j) { - if ($chars[$j] === '~') { - if (isset($chars[$j + 1])) { - if ($chars[$j + 1] === '*') { - $pattern .= preg_quote($chars[$j + 1], '/'); - ++$j; - } elseif ($chars[$j + 1] === '?') { - $pattern .= preg_quote($chars[$j + 1], '/'); - ++$j; - } - } else { - $pattern .= preg_quote($chars[$j], '/'); - } - } elseif ($chars[$j] === '*') { - $pattern .= '.*'; - } elseif ($chars[$j] === '?') { - $pattern .= '.{1}'; - } else { - $pattern .= preg_quote($chars[$j], '/'); - } - } - - $pattern .= '$/'; - if ((bool) preg_match($pattern, $lookupArrayValue)) { - // exact match - return $i + 1; - } - } elseif ($exactMatch) { - // exact match - return $i + 1; - } - } elseif (($matchType === 1) && $typeMatch && ($lookupArrayValue <= $lookupValue)) { - $i = array_search($i, $keySet); - - // The current value is the (first) match - return $i + 1; - } - } - } else { - $maxValueKey = null; - - // The basic algorithm is: - // Iterate and keep the highest match until the next element is smaller than the searched value. - // Return immediately if perfect match is found - foreach ($lookupArray as $i => $lookupArrayValue) { - $typeMatch = gettype($lookupValue) === gettype($lookupArrayValue); - $exactTypeMatch = $typeMatch && $lookupArrayValue === $lookupValue; - $nonOnlyNumericExactMatch = !$typeMatch && $lookupArrayValue === $lookupValue; - $exactMatch = $exactTypeMatch || $nonOnlyNumericExactMatch; - - if ($exactMatch) { - // Another "special" case. If a perfect match is found, - // the algorithm gives up immediately - return $i + 1; - } elseif ($typeMatch & $lookupArrayValue >= $lookupValue) { - $maxValueKey = $i + 1; - } elseif ($typeMatch & $lookupArrayValue < $lookupValue) { - //Excel algorithm gives up immediately if the first element is smaller than the searched value - break; - } - } - - if ($maxValueKey !== null) { - return $maxValueKey; - } - } - - // Unsuccessful in finding a match, return #N/A error value - return Functions::NA(); + return LookupRef\ExcelMatch::MATCH($lookupValue, $lookupArray, $matchType); } /** diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php b/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php new file mode 100644 index 00000000..71358bf3 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php @@ -0,0 +1,198 @@ +getMessage(); + } + + // MATCH() is not case sensitive, so we convert lookup value to be lower cased if it's a string type. + if (is_string($lookupValue)) { + $lookupValue = StringHelper::strToLower($lookupValue); + } + + $valueKey = null; + switch ($matchType) { + case self::MATCHTYPE_LARGEST_VALUE: + $valueKey = self::matchLargestValue($lookupArray, $lookupValue, $keySet); + + break; + case self::MATCHTYPE_FIRST_VALUE: + $valueKey = self::matchFirstValue($lookupArray, $lookupValue); + + break; + case self::MATCHTYPE_SMALLEST_VALUE: + default: + $valueKey = self::matchSmallestValue($lookupArray, $lookupValue); + } + + if ($valueKey !== null) { + return ++$valueKey; + } + + // Unsuccessful in finding a match, return #N/A error value + return Functions::NA(); + } + + private static function matchFirstValue($lookupArray, $lookupValue) + { + $wildcardLookup = ((bool) preg_match('/([\?\*])/', $lookupValue)); + $wildcard = WildcardMatch::wildcard($lookupValue); + + foreach ($lookupArray as $i => $lookupArrayValue) { + $typeMatch = ((gettype($lookupValue) === gettype($lookupArrayValue)) || + (is_numeric($lookupValue) && is_numeric($lookupArrayValue))); + + if ( + $typeMatch && is_string($lookupValue) && + $wildcardLookup && WildcardMatch::compare($lookupArrayValue, $wildcard) + ) { + // wildcard match + return $i; + } elseif ($lookupArrayValue === $lookupValue) { + // exact match + return $i; + } + } + + return null; + } + + private static function matchLargestValue($lookupArray, $lookupValue, $keySet) + { + foreach ($lookupArray as $i => $lookupArrayValue) { + $typeMatch = ((gettype($lookupValue) === gettype($lookupArrayValue)) || + (is_numeric($lookupValue) && is_numeric($lookupArrayValue))); + + if ($typeMatch && ($lookupArrayValue <= $lookupValue)) { + return array_search($i, $keySet); + } + } + + return null; + } + + private static function matchSmallestValue($lookupArray, $lookupValue) + { + $valueKey = null; + + // The basic algorithm is: + // Iterate and keep the highest match until the next element is smaller than the searched value. + // Return immediately if perfect match is found + foreach ($lookupArray as $i => $lookupArrayValue) { + $typeMatch = gettype($lookupValue) === gettype($lookupArrayValue); + + if ($lookupArrayValue === $lookupValue) { + // Another "special" case. If a perfect match is found, + // the algorithm gives up immediately + return $i; + } elseif ($typeMatch && $lookupArrayValue >= $lookupValue) { + $valueKey = $i; + } elseif ($typeMatch && $lookupArrayValue < $lookupValue) { + //Excel algorithm gives up immediately if the first element is smaller than the searched value + break; + } + } + + return $valueKey; + } + + private static function validateLookupValue($lookupValue): void + { + // Lookup_value type has to be number, text, or logical values + if ((!is_numeric($lookupValue)) && (!is_string($lookupValue)) && (!is_bool($lookupValue))) { + throw new Exception(Functions::NA()); + } + } + + private static function validateMatchType($matchType): void + { + // Match_type is 0, 1 or -1 + if ( + ($matchType !== self::MATCHTYPE_FIRST_VALUE) && + ($matchType !== self::MATCHTYPE_LARGEST_VALUE) && ($matchType !== self::MATCHTYPE_SMALLEST_VALUE) + ) { + throw new Exception(Functions::NA()); + } + } + + private static function validateLookupArray($lookupArray): void + { + // Lookup_array should not be empty + $lookupArraySize = count($lookupArray); + if ($lookupArraySize <= 0) { + throw new Exception(Functions::NA()); + } + } + + private static function prepareLookupArray($lookupArray, $matchType) + { + // Lookup_array should contain only number, text, or logical values, or empty (null) cells + foreach ($lookupArray as $i => $value) { + // check the type of the value + if ((!is_numeric($value)) && (!is_string($value)) && (!is_bool($value)) && ($value !== null)) { + throw new Exception(Functions::NA()); + } + // Convert strings to lowercase for case-insensitive testing + if (is_string($value)) { + $lookupArray[$i] = StringHelper::strToLower($value); + } + if ( + ($value === null) && + (($matchType == self::MATCHTYPE_LARGEST_VALUE) || ($matchType == self::MATCHTYPE_SMALLEST_VALUE)) + ) { + unset($lookupArray[$i]); + } + } + + return $lookupArray; + } +} diff --git a/tests/data/Calculation/LookupRef/MATCH.php b/tests/data/Calculation/LookupRef/MATCH.php index 671056dd..03d9bfff 100644 --- a/tests/data/Calculation/LookupRef/MATCH.php +++ b/tests/data/Calculation/LookupRef/MATCH.php @@ -26,7 +26,6 @@ return [ [2, 0, 0, 3], 0, ], - // Third argument = 1 [ 1, // Expected @@ -52,7 +51,6 @@ return [ [2, 0, 0, 3], 1, ], - // Third argument = -1 [ 1, // Expected @@ -96,7 +94,12 @@ return [ [8, 8, 3, 2], -1, ], - + [ // Default matchtype + 4, // Expected + 4, // Input + [2, 0, 0, 3], + null, + ], // match on ranges with empty cells [ 3, // Expected @@ -110,7 +113,6 @@ return [ [1, null, 4, null, null], 1, ], - // 0s are causing errors, because things like 0 == 'x' is true. Thanks PHP! [ 3, @@ -233,7 +235,7 @@ return [ [ 2, // Expected 'a*~*c', - ['aAAAAA', 'a123456*c', 'az'], + ['aAAAAA', 'a123456*c', 'az', 'alembic'], 0, ], [ @@ -272,4 +274,76 @@ return [ [1, 22, 'aaa'], 0, ], + [ + '#N/A', // Expected + 'abc', + [1, 22, 'aaa'], + 0, + ], + [ + '#N/A', // Expected (Invalid lookup value) + new DateTime('2021-03-11'), + [1, 22, 'aaa'], + 1, + ], + [ + '#N/A', // Expected (Invalid match type) + 'abc', + [1, 22, 'aaa'], + 123, + ], + [ + '#N/A', // Expected (Empty lookup array) + 'abc', + [], + 1, + ], + [ + 8, + 'A*e', + ['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'], + -1, + ], + [ + 2, + 'A*e', + ['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'], + 0, + ], + [ + '#N/A', + 'A*e', + ['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'], + 1, + ], + [ + 8, + 'A?s*e', + ['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'], + -1, + ], + [ + 5, + 'A?s*e', + ['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'], + 0, + ], + [ + '#N/A', + 'A*e', + ['Aardvark', 'Apple', 'Armadillo', 'Acre', 'Absolve', 'Amplitude', 'Adverse', 'Apartment'], + 1, + ], + [ + 8, + '*verse', + ['Obtuse', 'Amuse', 'Obverse', 'Inverse', 'Assurance', 'Amplitude', 'Adverse', 'Apartment'], + -1, + ], + [ + 3, + '*verse', + ['Obtuse', 'Amuse', 'Obverse', 'Inverse', 'Assurance', 'Amplitude', 'Adverse', 'Apartment'], + 0, + ], ]; From 0d1957ad2cc3fad228ef7709cfcbfb04b2927438 Mon Sep 17 00:00:00 2001 From: christof-b Date: Sat, 13 Mar 2021 12:03:05 +0100 Subject: [PATCH 106/187] Fix SpreadsheetML (xml) detection (#1917) * Fix SpreadsheetML (xml) detection (#1916) Replace the unrequired product signature by the required namespace definition for XML Spreadsheet. * Add summary to changelog (#1916) Co-authored-by: Christof Bachmann --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Reader/Xml.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5e273f8..2565a768 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Fix for [Issue #1887](https://github.com/PHPOffice/PhpSpreadsheet/issues/1887) - Lose Track of Selected Cells After Save - Fixed issue with Xlsx@listWorksheetInfo not returning any data - Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640) +- Fix for [Issue #1916](https://github.com/PHPOffice/PhpSpreadsheet/issues/1916) - Invalid signature check for XML files ## 1.17.1 - 2021-03-01 diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index b1df0ef5..a827d17a 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -116,7 +116,7 @@ class Xml extends BaseReader $signature = [ '', + 'xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet', ]; // Open file From 0ce8509a8cc5e9f0bc3166b0abfbbff2c4425b2b Mon Sep 17 00:00:00 2001 From: oleibman Date: Sat, 13 Mar 2021 03:06:30 -0800 Subject: [PATCH 107/187] Continue MathTrig Breakup - Trig Functions (#1905) * Continue MathTrig Breakup - Trig Functions Continuing the process of breaking MathTrip.php up into smaller classes. This round takes care of the trig and hyperbolic functions, plus a few others. - COS, COSH, ACOS, ACOSH - COT, COTH, ACOT, ACOTH - CSC, CSCH - SEC, SECH - SIN, SINH, ASIN, ASINH - TAN, TANH, ATAN, ATANH, ATAN2 - EVEN - ODD - SIGN There are no bug fixes in this PR, except that boolean arguments are now accepted for all these functions, as they are for Excel. Taking a cue from what has been done in Engineering, the parameter validation now happens in a routine which issues Exceptions for invalid values; this simplifies the code in the functions themselves. Consistent with earlier changes of this nature, the versions in the MathTrig class remain, with a doc block indicating deprecation, and a stub call to the new routines. I think several more iterations will be needed to break up MathTrig completely. --- .../Calculation/Calculation.php | 46 +-- src/PhpSpreadsheet/Calculation/MathTrig.php | 345 +++++------------- .../Calculation/MathTrig/Acos.php | 28 ++ .../Calculation/MathTrig/Acosh.php | 28 ++ .../Calculation/MathTrig/Acot.php | 28 ++ .../Calculation/MathTrig/Acoth.php | 30 ++ .../Calculation/MathTrig/Asin.php | 28 ++ .../Calculation/MathTrig/Asinh.php | 28 ++ .../Calculation/MathTrig/Atan.php | 28 ++ .../Calculation/MathTrig/Atan2.php | 46 +++ .../Calculation/MathTrig/Atanh.php | 28 ++ .../Calculation/MathTrig/Ceiling.php | 16 +- .../Calculation/MathTrig/CeilingMath.php | 31 +- .../Calculation/MathTrig/CeilingPrecise.php | 25 +- .../Calculation/MathTrig/Cos.php | 28 ++ .../Calculation/MathTrig/Cosh.php | 28 ++ .../Calculation/MathTrig/Cot.php | 28 ++ .../Calculation/MathTrig/Coth.php | 28 ++ .../Calculation/MathTrig/Csc.php | 28 ++ .../Calculation/MathTrig/Csch.php | 28 ++ .../Calculation/MathTrig/Even.php | 35 ++ .../Calculation/MathTrig/Floor.php | 18 +- .../Calculation/MathTrig/FloorMath.php | 22 +- .../Calculation/MathTrig/FloorPrecise.php | 14 +- .../Calculation/MathTrig/Helpers.php | 87 +++++ .../Calculation/MathTrig/IntClass.php | 12 +- .../Calculation/MathTrig/Mround.php | 34 +- .../Calculation/MathTrig/Odd.php | 38 ++ .../Calculation/MathTrig/Roman.php | 32 +- .../Calculation/MathTrig/Round.php | 14 +- .../Calculation/MathTrig/RoundDown.php | 31 +- .../Calculation/MathTrig/RoundUp.php | 31 +- .../Calculation/MathTrig/Sec.php | 28 ++ .../Calculation/MathTrig/Sech.php | 28 ++ .../Calculation/MathTrig/Sign.php | 29 ++ .../Calculation/MathTrig/Sin.php | 28 ++ .../Calculation/MathTrig/Sinh.php | 28 ++ .../Calculation/MathTrig/Tan.php | 28 ++ .../Calculation/MathTrig/Tanh.php | 28 ++ .../Calculation/MathTrig/Trunc.php | 15 +- .../Functions/MathTrig/AcosTest.php | 11 +- .../Functions/MathTrig/AcoshTest.php | 11 +- .../Functions/MathTrig/AcotTest.php | 23 +- .../Functions/MathTrig/AcothTest.php | 23 +- .../Functions/MathTrig/AsinTest.php | 11 +- .../Functions/MathTrig/AsinhTest.php | 11 +- .../Functions/MathTrig/Atan2Test.php | 25 +- .../Functions/MathTrig/AtanTest.php | 11 +- .../Functions/MathTrig/AtanhTest.php | 11 +- .../Functions/MathTrig/CosTest.php | 11 +- .../Functions/MathTrig/CoshTest.php | 11 +- .../Functions/MathTrig/CotTest.php | 23 +- .../Functions/MathTrig/CothTest.php | 23 +- .../Functions/MathTrig/CscTest.php | 23 +- .../Functions/MathTrig/CschTest.php | 23 +- .../Functions/MathTrig/EvenTest.php | 19 +- .../Functions/MathTrig/MovedFunctionsTest.php | 32 ++ .../Functions/MathTrig/OddTest.php | 19 +- .../Functions/MathTrig/SecTest.php | 23 +- .../Functions/MathTrig/SechTest.php | 23 +- .../Functions/MathTrig/SignTest.php | 22 +- .../Functions/MathTrig/SinTest.php | 11 +- .../Functions/MathTrig/SinhTest.php | 11 +- .../Functions/MathTrig/TanTest.php | 11 +- .../Functions/MathTrig/TanhTest.php | 11 +- tests/data/Calculation/MathTrig/ACOS.php | 14 +- tests/data/Calculation/MathTrig/ACOSH.php | 14 +- tests/data/Calculation/MathTrig/ACOT.php | 75 +--- tests/data/Calculation/MathTrig/ACOTH.php | 75 +--- tests/data/Calculation/MathTrig/ASIN.php | 14 +- tests/data/Calculation/MathTrig/ASINH.php | 16 +- tests/data/Calculation/MathTrig/ATAN.php | 16 +- tests/data/Calculation/MathTrig/ATAN2.php | 84 +---- tests/data/Calculation/MathTrig/ATANH.php | 16 +- tests/data/Calculation/MathTrig/COS.php | 18 +- tests/data/Calculation/MathTrig/COSH.php | 12 +- tests/data/Calculation/MathTrig/COT.php | 65 +--- tests/data/Calculation/MathTrig/COTH.php | 76 +--- tests/data/Calculation/MathTrig/CSC.php | 65 +--- tests/data/Calculation/MathTrig/CSCH.php | 75 +--- tests/data/Calculation/MathTrig/EVEN.php | 88 +---- tests/data/Calculation/MathTrig/ODD.php | 68 +--- tests/data/Calculation/MathTrig/SEC.php | 85 ++--- tests/data/Calculation/MathTrig/SECH.php | 75 +--- tests/data/Calculation/MathTrig/SIGN.php | 71 +--- tests/data/Calculation/MathTrig/SIN.php | 16 +- tests/data/Calculation/MathTrig/SINH.php | 14 +- tests/data/Calculation/MathTrig/TAN.php | 20 +- tests/data/Calculation/MathTrig/TANH.php | 14 +- 89 files changed, 1619 insertions(+), 1383 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Acos.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Acosh.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Acot.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Acoth.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Asin.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Asinh.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Atan.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Atan2.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Atanh.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Cos.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Cosh.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Cot.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Coth.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Csc.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Csch.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Even.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Odd.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sec.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sech.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sign.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sin.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sinh.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Tan.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Tanh.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 80b6d47b..1db4722b 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -243,22 +243,22 @@ class Calculation ], 'ACOS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinACOS'], + 'functionCall' => [MathTrig\Acos::class, 'funcAcos'], 'argumentCount' => '1', ], 'ACOSH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinACOSH'], + 'functionCall' => [MathTrig\Acosh::class, 'funcAcosh'], 'argumentCount' => '1', ], 'ACOT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ACOT'], + 'functionCall' => [MathTrig\Acot::class, 'funcAcot'], 'argumentCount' => '1', ], 'ACOTH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ACOTH'], + 'functionCall' => [MathTrig\Acoth::class, 'funcAcoth'], 'argumentCount' => '1', ], 'ADDRESS' => [ @@ -303,27 +303,27 @@ class Calculation ], 'ASIN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinASIN'], + 'functionCall' => [MathTrig\Asin::class, 'funcAsin'], 'argumentCount' => '1', ], 'ASINH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinASINH'], + 'functionCall' => [MathTrig\Asinh::class, 'funcAsinh'], 'argumentCount' => '1', ], 'ATAN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinATAN'], + 'functionCall' => [MathTrig\Atan::class, 'funcAtan'], 'argumentCount' => '1', ], 'ATAN2' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ATAN2'], + 'functionCall' => [MathTrig\Atan2::class, 'funcAtan2'], 'argumentCount' => '2', ], 'ATANH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinATANH'], + 'functionCall' => [MathTrig\Atanh::class, 'funcAtanh'], 'argumentCount' => '1', ], 'AVEDEV' => [ @@ -605,22 +605,22 @@ class Calculation ], 'COS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinCOS'], + 'functionCall' => [MathTrig\Cos::class, 'funcCos'], 'argumentCount' => '1', ], 'COSH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinCOSH'], + 'functionCall' => [MathTrig\Cosh::class, 'funcCosh'], 'argumentCount' => '1', ], 'COT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'COT'], + 'functionCall' => [MathTrig\Cot::class, 'funcCot'], 'argumentCount' => '1', ], 'COTH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'COTH'], + 'functionCall' => [MathTrig\Coth::class, 'funcCoth'], 'argumentCount' => '1', ], 'COUNT' => [ @@ -700,12 +700,12 @@ class Calculation ], 'CSC' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'CSC'], + 'functionCall' => [MathTrig\Csc::class, 'funcCsc'], 'argumentCount' => '1', ], 'CSCH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'CSCH'], + 'functionCall' => [MathTrig\Csch::class, 'funcCsch'], 'argumentCount' => '1', ], 'CUBEKPIMEMBER' => [ @@ -965,7 +965,7 @@ class Calculation ], 'EVEN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'EVEN'], + 'functionCall' => [MathTrig\Even::class, 'funcEven'], 'argumentCount' => '1', ], 'EXACT' => [ @@ -1856,7 +1856,7 @@ class Calculation ], 'ODD' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ODD'], + 'functionCall' => [MathTrig\Odd::class, 'funcOdd'], 'argumentCount' => '1', ], 'ODDFPRICE' => [ @@ -2165,12 +2165,12 @@ class Calculation ], 'SEC' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SEC'], + 'functionCall' => [MathTrig\Sec::class, 'funcSec'], 'argumentCount' => '1', ], 'SECH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SECH'], + 'functionCall' => [MathTrig\Sech::class, 'funcSech'], 'argumentCount' => '1', ], 'SECOND' => [ @@ -2200,7 +2200,7 @@ class Calculation ], 'SIGN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SIGN'], + 'functionCall' => [MathTrig\Sign::class, 'funcSign'], 'argumentCount' => '1', ], 'SIN' => [ @@ -2210,7 +2210,7 @@ class Calculation ], 'SINH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinSINH'], + 'functionCall' => [MathTrig\Sinh::class, 'funcSinh'], 'argumentCount' => '1', ], 'SKEW' => [ @@ -2366,12 +2366,12 @@ class Calculation ], 'TAN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinTAN'], + 'functionCall' => [MathTrig\Tan::class, 'funcTan'], 'argumentCount' => '1', ], 'TANH' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinTANH'], + 'functionCall' => [MathTrig\Tanh::class, 'funcTanh'], 'argumentCount' => '1', ], 'TBILLEQ' => [ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index e72e24cd..f3d8351d 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -133,6 +133,8 @@ class MathTrig * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard * PHP atan2() function, so we need to reverse them here before calling the PHP atan() function. * + * @Deprecated 2.0.0 Use the funcAtan2 method in the MathTrig\Atan2 class instead + * * Excel Function: * ATAN2(xCoordinate,yCoordinate) * @@ -143,27 +145,7 @@ class MathTrig */ public static function ATAN2($xCoordinate = null, $yCoordinate = null) { - $xCoordinate = Functions::flattenSingleValue($xCoordinate); - $yCoordinate = Functions::flattenSingleValue($yCoordinate); - - $xCoordinate = $xCoordinate ?? 0.0; - $yCoordinate = $yCoordinate ?? 0.0; - - if ( - ((is_numeric($xCoordinate)) || (is_bool($xCoordinate))) && - ((is_numeric($yCoordinate))) || (is_bool($yCoordinate)) - ) { - $xCoordinate = (float) $xCoordinate; - $yCoordinate = (float) $yCoordinate; - - if (($xCoordinate == 0) && ($yCoordinate == 0)) { - return Functions::DIV0(); - } - - return atan2($yCoordinate, $xCoordinate); - } - - return Functions::VALUE(); + return MathTrig\Atan2::funcAtan2($xCoordinate, $yCoordinate); } /** @@ -226,8 +208,6 @@ class MathTrig * @param float $significance the multiple to which you want to round * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function CEILING($number, $significance = null) { @@ -269,6 +249,8 @@ class MathTrig /** * EVEN. * + * @Deprecated 2.0.0 Use the funcEven method in the MathTrig\Even class instead + * * Returns number rounded up to the nearest even integer. * You can use this function for processing items that come in twos. For example, * a packing crate accepts rows of one or two items. The crate is full when @@ -284,26 +266,17 @@ class MathTrig */ public static function EVEN($number) { - $number = Functions::flattenSingleValue($number); - - if ($number === null) { - return 0; - } elseif (is_bool($number)) { - $number = (int) $number; - } - - if (is_numeric($number)) { - return self::getEven((float) $number); - } - - return Functions::VALUE(); + return MathTrig\Even::funcEven($number); } + /** + * Helper function for Even. + * + * @Deprecated 2.0.0 Use the getEven method in the MathTrig\Helpers class instead + */ public static function getEven(float $number): int { - $significance = 2 * self::returnSign($number); - - return (int) MathTrig\Ceiling::funcCeiling($number, $significance); + return (int) MathTrig\Helpers::getEven($number); } /** @@ -395,8 +368,6 @@ class MathTrig * @param float $significance Significance * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function FLOOR($number, $significance = null) { @@ -420,8 +391,6 @@ class MathTrig * @param int $mode direction to round negative numbers * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function FLOORMATH($number, $significance = null, $mode = 0) { @@ -444,8 +413,6 @@ class MathTrig * @param float $significance Significance * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function FLOORPRECISE($number, $significance = 1) { @@ -472,8 +439,6 @@ class MathTrig * @param float $number Number to cast to an integer * * @return int|string Integer value, or a string containing an error - * - * @codeCoverageIgnore */ public static function INT($number) { @@ -797,8 +762,6 @@ class MathTrig * @param int $multiple Multiple to which you want to round $number * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function MROUND($number, $multiple) { @@ -847,36 +810,15 @@ class MathTrig * * Returns number rounded up to the nearest odd integer. * + * @Deprecated 2.0.0 Use the funcOdd method in the MathTrig\Odd class instead + * * @param float $number Number to round * * @return int|string Rounded Number, or a string containing an error */ public static function ODD($number) { - $number = Functions::flattenSingleValue($number); - - if ($number === null) { - return 1; - } elseif (is_bool($number)) { - return 1; - } elseif (is_numeric($number)) { - $significance = self::returnSign($number); - if ($significance == 0) { - return 1; - } - - $result = MathTrig\Ceiling::funcCeiling($number, $significance); - if (is_string($result)) { - return $result; - } - if ($result == self::getEven((float) $result)) { - $result += $significance; - } - - return (int) $result; - } - - return Functions::VALUE(); + return MathTrig\Odd::funcOdd($number); } /** @@ -1015,8 +957,6 @@ class MathTrig * @param mixed $style Number indicating one of five possible forms * * @return string Roman numeral, or a string containing an error - * - * @codeCoverageIgnore */ public static function ROMAN($aValue, $style = 0) { @@ -1036,8 +976,6 @@ class MathTrig * @param int $digits Number of digits to which you want to round $number * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function ROUNDUP($number, $digits) { @@ -1057,8 +995,6 @@ class MathTrig * @param int $digits Number of digits to which you want to round $number * * @return float|string Rounded Number, or a string containing an error - * - * @codeCoverageIgnore */ public static function ROUNDDOWN($number, $digits) { @@ -1109,27 +1045,25 @@ class MathTrig * Determines the sign of a number. Returns 1 if the number is positive, zero (0) * if the number is 0, and -1 if the number is negative. * + * @Deprecated 2.0.0 Use the funcSign method in the MathTrig\Sign class instead + * * @param float $number Number to round * * @return int|string sign value, or a string containing an error */ public static function SIGN($number) { - $number = Functions::flattenSingleValue($number); - - if (is_bool($number)) { - return (int) $number; - } - if (is_numeric($number)) { - return self::returnSign($number); - } - - return Functions::VALUE(); + return MathTrig\Sign::funcSign($number); } + /** + * returnSign = returns 0/-1/+1. + * + * @Deprecated 2.0.0 Use the returnSign method in the MathTrig\Helpers class instead + */ public static function returnSign(float $number): int { - return $number ? (($number > 0) ? 1 : -1) : 0; + return MathTrig\Helpers::returnSign($number); } /** @@ -1486,8 +1420,6 @@ class MathTrig * @param int $digits * * @return float|string Truncated value, or a string containing an error - * - * @codeCoverageIgnore */ public static function TRUNC($value = 0, $digits = 0) { @@ -1499,21 +1431,15 @@ class MathTrig * * Returns the secant of an angle. * + * @Deprecated 2.0.0 Use the funcSec method in the MathTrig\Sec class instead + * * @param float $angle Number * * @return float|string The secant of the angle */ public static function SEC($angle) { - $angle = Functions::flattenSingleValue($angle); - - if (!is_numeric($angle)) { - return Functions::VALUE(); - } - - $result = cos($angle); - - return self::verySmallDivisor($result) ? Functions::DIV0() : (1 / $result); + return MathTrig\Sec::funcSec($angle); } /** @@ -1521,21 +1447,15 @@ class MathTrig * * Returns the hyperbolic secant of an angle. * + * @Deprecated 2.0.0 Use the funcSech method in the MathTrig\Sech class instead + * * @param float $angle Number * * @return float|string The hyperbolic secant of the angle */ public static function SECH($angle) { - $angle = Functions::flattenSingleValue($angle); - - if (!is_numeric($angle)) { - return Functions::VALUE(); - } - - $result = cosh($angle); - - return ($result == 0.0) ? Functions::DIV0() : 1 / $result; + return MathTrig\Sech::funcSech($angle); } /** @@ -1543,21 +1463,15 @@ class MathTrig * * Returns the cosecant of an angle. * + * @Deprecated 2.0.0 Use the funcCsc method in the MathTrig\Csc class instead + * * @param float $angle Number * * @return float|string The cosecant of the angle */ public static function CSC($angle) { - $angle = Functions::flattenSingleValue($angle); - - if (!is_numeric($angle)) { - return Functions::VALUE(); - } - - $result = sin($angle); - - return self::verySmallDivisor($result) ? Functions::DIV0() : (1 / $result); + return MathTrig\Csc::funcCsc($angle); } /** @@ -1565,21 +1479,15 @@ class MathTrig * * Returns the hyperbolic cosecant of an angle. * + * @Deprecated 2.0.0 Use the funcCsch method in the MathTrig\Csch class instead + * * @param float $angle Number * * @return float|string The hyperbolic cosecant of the angle */ public static function CSCH($angle) { - $angle = Functions::flattenSingleValue($angle); - - if (!is_numeric($angle)) { - return Functions::VALUE(); - } - - $result = sinh($angle); - - return ($result == 0.0) ? Functions::DIV0() : 1 / $result; + return MathTrig\Csch::funcCsch($angle); } /** @@ -1587,21 +1495,15 @@ class MathTrig * * Returns the cotangent of an angle. * + * @Deprecated 2.0.0 Use the funcCot method in the MathTrig\Cot class instead + * * @param float $angle Number * * @return float|string The cotangent of the angle */ public static function COT($angle) { - $angle = Functions::flattenSingleValue($angle); - - if (!is_numeric($angle)) { - return Functions::VALUE(); - } - - $result = sin($angle); - - return self::verySmallDivisor($result) ? Functions::DIV0() : (cos($angle) / $result); + return MathTrig\Cot::funcCot($angle); } /** @@ -1609,21 +1511,15 @@ class MathTrig * * Returns the hyperbolic cotangent of an angle. * + * @Deprecated 2.0.0 Use the funcCoth method in the MathTrig\Coth class instead + * * @param float $angle Number * * @return float|string The hyperbolic cotangent of the angle */ public static function COTH($angle) { - $angle = Functions::flattenSingleValue($angle); - - if (!is_numeric($angle)) { - return Functions::VALUE(); - } - - $result = tanh($angle); - - return ($result == 0.0) ? Functions::DIV0() : 1 / $result; + return MathTrig\Coth::funcCoth($angle); } /** @@ -1631,31 +1527,29 @@ class MathTrig * * Returns the arccotangent of a number. * + * @Deprecated 2.0.0 Use the funcAcot method in the MathTrig\Acot class instead + * * @param float $number Number * * @return float|string The arccotangent of the number */ public static function ACOT($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return (M_PI / 2) - atan($number); + return MathTrig\Acot::funcAcot($number); } /** * Return NAN or value depending on argument. * + * @Deprecated 2.0.0 Use the numberOrNan method in the MathTrig\Helpers class instead + * * @param float $result Number * * @return float|string */ public static function numberOrNan($result) { - return is_nan($result) ? Functions::NAN() : $result; + return MathTrig\Helpers::numberOrNan($result); } /** @@ -1663,21 +1557,15 @@ class MathTrig * * Returns the hyperbolic arccotangent of a number. * + * @Deprecated 2.0.0 Use the funcAcoth method in the MathTrig\Acoth class instead + * * @param float $number Number * * @return float|string The hyperbolic arccotangent of the number */ public static function ACOTH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - $result = log(($number + 1) / ($number - 1)) / 2; - - return self::numberOrNan($result); + return MathTrig\Acoth::funcAcoth($number); } /** @@ -1693,8 +1581,6 @@ class MathTrig * @param mixed $precision Should be int * * @return float|string Rounded number - * - * @codeCoverageIgnore */ public static function builtinROUND($number, $precision) { @@ -1724,6 +1610,8 @@ class MathTrig /** * ACOS. * + * @Deprecated 2.0.0 Use the funcAcos method in the MathTrig\Acos class instead + * * Returns the result of builtin function acos after validating args. * * @param mixed $number Should be numeric @@ -1732,13 +1620,7 @@ class MathTrig */ public static function builtinACOS($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return self::numberOrNan(acos($number)); + return MathTrig\Acos::funcAcos($number); } /** @@ -1746,19 +1628,15 @@ class MathTrig * * Returns the result of builtin function acosh after validating args. * + * @Deprecated 2.0.0 Use the funcAcosh method in the MathTrig\Acosh class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinACOSH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return self::numberOrNan(acosh($number)); + return MathTrig\Acosh::funcAcosh($number); } /** @@ -1766,19 +1644,15 @@ class MathTrig * * Returns the result of builtin function asin after validating args. * + * @Deprecated 2.0.0 Use the funcAsin method in the MathTrig\Asin class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinASIN($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return self::numberOrNan(asin($number)); + return MathTrig\Asin::funcAsin($number); } /** @@ -1786,39 +1660,31 @@ class MathTrig * * Returns the result of builtin function asinh after validating args. * + * @Deprecated 2.0.0 Use the funcAsinh method in the MathTrig\Asinh class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinASINH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return asinh($number); + return MathTrig\Asinh::funcAsinh($number); } /** - * ASIN. + * ATAN. * * Returns the result of builtin function atan after validating args. * + * @Deprecated 2.0.0 Use the funcAtan method in the MathTrig\Atan class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinATAN($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return self::numberOrNan(atan($number)); + return MathTrig\Atan::funcAtan($number); } /** @@ -1826,19 +1692,15 @@ class MathTrig * * Returns the result of builtin function atanh after validating args. * + * @Deprecated 2.0.0 Use the funcAtanh method in the MathTrig\Atanh class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinATANH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return atanh($number); + return MathTrig\Atanh::funcAtanh($number); } /** @@ -1846,19 +1708,15 @@ class MathTrig * * Returns the result of builtin function cos after validating args. * + * @Deprecated 2.0.0 Use the funcCos method in the MathTrig\Cos class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinCOS($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return cos($number); + return MathTrig\Cos::funcCos($number); } /** @@ -1866,19 +1724,15 @@ class MathTrig * * Returns the result of builtin function cos after validating args. * + * @Deprecated 2.0.0 Use the funcCosh method in the MathTrig\Cosh class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinCOSH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return cosh($number); + return MathTrig\Cosh::funcCosh($number); } /** @@ -1984,6 +1838,8 @@ class MathTrig /** * SIN. * + * @Deprecated 2.0.0 Use the funcSin method in the MathTrig\Sin class instead + * * Returns the result of builtin function sin after validating args. * * @param mixed $number Should be numeric @@ -1992,18 +1848,14 @@ class MathTrig */ public static function builtinSIN($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return sin($number); + return MathTrig\Sin::funcSin($number); } /** * SINH. * + * @Deprecated 2.0.0 Use the funcSinh method in the MathTrig\Sinh class instead + * * Returns the result of builtin function sinh after validating args. * * @param mixed $number Should be numeric @@ -2012,13 +1864,7 @@ class MathTrig */ public static function builtinSINH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return sinh($number); + return MathTrig\Sinh::funcSinh($number); } /** @@ -2046,19 +1892,15 @@ class MathTrig * * Returns the result of builtin function tan after validating args. * + * @Deprecated 2.0.0 Use the funcTan method in the MathTrig\Tan class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinTAN($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return self::verySmallDivisor(cos($number)) ? Functions::DIV0() : tan($number); + return MathTrig\Tan::funcTan($number); } /** @@ -2066,29 +1908,22 @@ class MathTrig * * Returns the result of builtin function sinh after validating args. * + * @Deprecated 2.0.0 Use the funcTanh method in the MathTrig\Tanh class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinTANH($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return tanh($number); - } - - private static function verySmallDivisor(float $number): bool - { - return abs($number) < 1.0E-12; + return MathTrig\Tanh::funcTanh($number); } /** * Many functions accept null/false/true argument treated as 0/0/1. * + * @Deprecated 2.0.0 Use the validateNumericNullBool method in the MathTrig\Helpers class instead + * * @param mixed $number */ public static function nullFalseTrueToNumber(&$number): void diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Acos.php b/src/PhpSpreadsheet/Calculation/MathTrig/Acos.php new file mode 100644 index 00000000..20d645f2 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Acos.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(acos($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Acosh.php b/src/PhpSpreadsheet/Calculation/MathTrig/Acosh.php new file mode 100644 index 00000000..f77d3a09 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Acosh.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(acosh($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Acot.php b/src/PhpSpreadsheet/Calculation/MathTrig/Acot.php new file mode 100644 index 00000000..1024f9f6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Acot.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return (M_PI / 2) - atan($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Acoth.php b/src/PhpSpreadsheet/Calculation/MathTrig/Acoth.php new file mode 100644 index 00000000..42bdc181 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Acoth.php @@ -0,0 +1,30 @@ +getMessage(); + } + + $result = ($number === 1) ? NAN : (log(($number + 1) / ($number - 1)) / 2); + + return Helpers::numberOrNan($result); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Asin.php b/src/PhpSpreadsheet/Calculation/MathTrig/Asin.php new file mode 100644 index 00000000..e30ab04c --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Asin.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(asin($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Asinh.php b/src/PhpSpreadsheet/Calculation/MathTrig/Asinh.php new file mode 100644 index 00000000..35a3ae26 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Asinh.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(asinh($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Atan.php b/src/PhpSpreadsheet/Calculation/MathTrig/Atan.php new file mode 100644 index 00000000..3e57f048 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Atan.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(atan($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Atan2.php b/src/PhpSpreadsheet/Calculation/MathTrig/Atan2.php new file mode 100644 index 00000000..2ea975a8 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Atan2.php @@ -0,0 +1,46 @@ +getMessage(); + } + + if (($xCoordinate == 0) && ($yCoordinate == 0)) { + return Functions::DIV0(); + } + + return atan2($yCoordinate, $xCoordinate); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Atanh.php b/src/PhpSpreadsheet/Calculation/MathTrig/Atanh.php new file mode 100644 index 00000000..a9723f16 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Atanh.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(atanh($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php b/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php index 6fdd6165..1085158a 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Ceiling.php @@ -4,7 +4,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; use Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Ceiling { @@ -26,19 +25,18 @@ class Ceiling */ public static function funcCeiling($number, $significance = null) { - MathTrig::nullFalseTrueToNumber($number); - $significance = Functions::flattenSingleValue($significance); - if ($significance === null) { self::floorCheck1Arg(); - $significance = ((float) $number < 0) ? -1 : 1; } - if ((is_numeric($number)) && (is_numeric($significance))) { - return self::argumentsOk((float) $number, (float) $significance); + try { + $number = Helpers::validateNumericNullBool($number); + $significance = Helpers::validateNumericNullSubstitution($significance, ($number < 0) ? -1 : 1); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + return self::argumentsOk((float) $number, (float) $significance); } /** @@ -51,7 +49,7 @@ class Ceiling if (empty($number * $significance)) { return 0.0; } - if (MathTrig::returnSign($number) == MathTrig::returnSign($significance)) { + if (Helpers::returnSign($number) == Helpers::returnSign($significance)) { return ceil($number / $significance) * $significance; } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/CeilingMath.php b/src/PhpSpreadsheet/Calculation/MathTrig/CeilingMath.php index f94d1fe0..e41e9d09 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/CeilingMath.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/CeilingMath.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class CeilingMath { @@ -23,26 +22,22 @@ class CeilingMath */ public static function funcCeilingMath($number, $significance = null, $mode = 0) { - MathTrig::nullFalseTrueToNumber($number); - $significance = Functions::flattenSingleValue($significance); - $mode = Functions::flattenSingleValue($mode); - - if ($significance === null) { - $significance = ((float) $number < 0) ? -1 : 1; + try { + $number = Helpers::validateNumericNullBool($number); + $significance = Helpers::validateNumericNullSubstitution($significance, ($number < 0) ? -1 : 1); + $mode = Helpers::validateNumericNullSubstitution($mode, null); + } catch (Exception $e) { + return $e->getMessage(); } - if (is_numeric($number) && is_numeric($significance) && is_numeric($mode)) { - if (empty($significance * $number)) { - return 0.0; - } - if (self::ceilingMathTest((float) $significance, (float) $number, (int) $mode)) { - return floor($number / $significance) * $significance; - } - - return ceil($number / $significance) * $significance; + if (empty($significance * $number)) { + return 0.0; + } + if (self::ceilingMathTest((float) $significance, (float) $number, (int) $mode)) { + return floor($number / $significance) * $significance; } - return Functions::VALUE(); + return ceil($number / $significance) * $significance; } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/CeilingPrecise.php b/src/PhpSpreadsheet/Calculation/MathTrig/CeilingPrecise.php index d9c61c41..1bc4504b 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/CeilingPrecise.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/CeilingPrecise.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class CeilingPrecise { @@ -22,18 +21,18 @@ class CeilingPrecise */ public static function funcCeilingPrecise($number, $significance = 1) { - MathTrig::nullFalseTrueToNumber($number); - $significance = Functions::flattenSingleValue($significance); - - if ((is_numeric($number)) && (is_numeric($significance))) { - if ($significance == 0.0) { - return 0.0; - } - $result = $number / abs($significance); - - return ceil($result) * $significance * (($significance < 0) ? -1 : 1); + try { + $number = Helpers::validateNumericNullBool($number); + $significance = Helpers::validateNumericNullSubstitution($significance, null); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if (!$significance) { + return 0.0; + } + $result = $number / abs($significance); + + return ceil($result) * $significance * (($significance < 0) ? -1 : 1); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Cos.php b/src/PhpSpreadsheet/Calculation/MathTrig/Cos.php new file mode 100644 index 00000000..2dfed782 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Cos.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return cos($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Cosh.php b/src/PhpSpreadsheet/Calculation/MathTrig/Cosh.php new file mode 100644 index 00000000..3e806cd6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Cosh.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return cosh($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Cot.php b/src/PhpSpreadsheet/Calculation/MathTrig/Cot.php new file mode 100644 index 00000000..1cf5c6b4 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Cot.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(cos($angle), sin($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Coth.php b/src/PhpSpreadsheet/Calculation/MathTrig/Coth.php new file mode 100644 index 00000000..c80ec93e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Coth.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(1.0, tanh($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Csc.php b/src/PhpSpreadsheet/Calculation/MathTrig/Csc.php new file mode 100644 index 00000000..325637b8 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Csc.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(1.0, sin($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Csch.php b/src/PhpSpreadsheet/Calculation/MathTrig/Csch.php new file mode 100644 index 00000000..8a045203 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Csch.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(1.0, sinh($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Even.php b/src/PhpSpreadsheet/Calculation/MathTrig/Even.php new file mode 100644 index 00000000..ac79a211 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Even.php @@ -0,0 +1,35 @@ +getMessage(); + } + + return Helpers::getEven($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Floor.php b/src/PhpSpreadsheet/Calculation/MathTrig/Floor.php index 0c65ee7c..f178b324 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Floor.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Floor.php @@ -4,7 +4,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; use Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Floor { @@ -31,19 +30,18 @@ class Floor */ public static function funcFloor($number, $significance = null) { - MathTrig::nullFalseTrueToNumber($number); - $significance = Functions::flattenSingleValue($significance); - if ($significance === null) { self::floorCheck1Arg(); - $significance = MathTrig::returnSign((float) $number); } - if ((is_numeric($number)) && (is_numeric($significance))) { - return self::argumentsOk((float) $number, (float) $significance); + try { + $number = Helpers::validateNumericNullBool($number); + $significance = Helpers::validateNumericNullSubstitution($significance, ($number < 0) ? -1 : 1); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + return self::argumentsOk((float) $number, (float) $significance); } /** @@ -59,10 +57,10 @@ class Floor if ($number == 0.0) { return 0.0; } - if (MathTrig::returnSign($significance) == 1) { + if (Helpers::returnSign($significance) == 1) { return floor($number / $significance) * $significance; } - if (MathTrig::returnSign($number) == -1 && MathTrig::returnSign($significance) == -1) { + if (Helpers::returnSign($number) == -1 && Helpers::returnSign($significance) == -1) { return floor($number / $significance) * $significance; } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/FloorMath.php b/src/PhpSpreadsheet/Calculation/MathTrig/FloorMath.php index cba78a53..8b922829 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/FloorMath.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/FloorMath.php @@ -2,8 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class FloorMath { @@ -23,19 +23,15 @@ class FloorMath */ public static function funcFloorMath($number, $significance = null, $mode = 0) { - MathTrig::nullFalseTrueToNumber($number); - $significance = Functions::flattenSingleValue($significance); - $mode = Functions::flattenSingleValue($mode); - - if ($significance === null) { - $significance = ((float) $number < 0) ? -1 : 1; + try { + $number = Helpers::validateNumericNullBool($number); + $significance = Helpers::validateNumericNullSubstitution($significance, ($number < 0) ? -1 : 1); + $mode = Helpers::validateNumericNullSubstitution($mode, null); + } catch (Exception $e) { + return $e->getMessage(); } - if (is_numeric($number) && is_numeric($significance) && is_numeric($mode)) { - return self::argsOk((float) $number, (float) $significance, (int) $mode); - } - - return Functions::VALUE(); + return self::argsOk((float) $number, (float) $significance, (int) $mode); } /** @@ -63,6 +59,6 @@ class FloorMath */ private static function floorMathTest(float $number, float $significance, int $mode): bool { - return mathTrig::returnSign($significance) == -1 || (mathTrig::returnSign($number) == -1 && !empty($mode)); + return Helpers::returnSign($significance) == -1 || (Helpers::returnSign($number) == -1 && !empty($mode)); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/FloorPrecise.php b/src/PhpSpreadsheet/Calculation/MathTrig/FloorPrecise.php index 07990aa5..3ce34dc4 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/FloorPrecise.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/FloorPrecise.php @@ -2,8 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class FloorPrecise { @@ -22,14 +22,14 @@ class FloorPrecise */ public static function funcFloorPrecise($number, $significance = 1) { - MathTrig::nullFalseTrueToNumber($number); - $significance = Functions::flattenSingleValue($significance); - - if ((is_numeric($number)) && (is_numeric($significance))) { - return self::argumentsOk((float) $number, (float) $significance); + try { + $number = Helpers::validateNumericNullBool($number); + $significance = Helpers::validateNumericNullSubstitution($significance, null); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + return self::argumentsOk((float) $number, (float) $significance); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php new file mode 100644 index 00000000..63b5082c --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php @@ -0,0 +1,87 @@ + 0) ? 1 : -1) : 0; + } + + public static function getEven(float $number): float + { + $significance = 2 * self::returnSign($number); + + return $significance ? (ceil($number / $significance) * $significance) : 0; + } + + /** + * Return NAN or value depending on argument. + * + * @param float $result Number + * + * @return float|string + */ + public static function numberOrNan($result) + { + return is_nan($result) ? Functions::NAN() : $result; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php b/src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php index 46784908..e43fe65c 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/IntClass.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class IntClass { @@ -21,11 +20,12 @@ class IntClass */ public static function funcInt($number) { - MathTrig::nullFalseTrueToNumber($number); - if (is_numeric($number)) { - return (int) floor($number); + try { + $number = Helpers::validateNumericNullBool($number); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + return (int) floor($number); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Mround.php b/src/PhpSpreadsheet/Calculation/MathTrig/Mround.php index 4c040dce..d1b32aa7 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Mround.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Mround.php @@ -2,8 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Mround { @@ -19,24 +19,22 @@ class Mround */ public static function funcMround($number, $multiple) { - $number = Functions::flattenSingleValue($number); - $number = $number ?? 0; - - $multiple = Functions::flattenSingleValue($multiple); - - if ((is_numeric($number)) && (is_numeric($multiple))) { - if ($number == 0 || $multiple == 0) { - return 0; - } - if ((MathTrig::SIGN($number)) == (MathTrig::SIGN($multiple))) { - $multiplier = 1 / $multiple; - - return round($number * $multiplier) / $multiplier; - } - - return Functions::NAN(); + try { + $number = Helpers::validateNumericNullSubstitution($number, 0); + $multiple = Helpers::validateNumericNullSubstitution($multiple, null); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if ($number == 0 || $multiple == 0) { + return 0; + } + if ((Helpers::returnSign($number)) == (Helpers::returnSign($multiple))) { + $multiplier = 1 / $multiple; + + return round($number * $multiplier) / $multiplier; + } + + return Functions::NAN(); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Odd.php b/src/PhpSpreadsheet/Calculation/MathTrig/Odd.php new file mode 100644 index 00000000..b8ef3dd0 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Odd.php @@ -0,0 +1,38 @@ +getMessage(); + } + + $significance = Helpers::returnSign($number); + if ($significance == 0) { + return 1; + } + + $result = ceil($number / $significance) * $significance; + if ($result == Helpers::getEven($result)) { + $result += $significance; + } + + return $result; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php b/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php index a461001b..05ecb531 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Roman.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Roman @@ -823,31 +824,16 @@ class Roman */ public static function funcRoman($aValue, $style = 0) { - $aValue = Functions::flattenSingleValue($aValue); - self::nullFalseTrueToNumber($aValue); - $style = Functions::flattenSingleValue($style); - if (is_bool($style)) { - $style = $style ? 0 : 4; - } - if (!is_numeric($aValue) || !is_numeric($style)) { - return Functions::VALUE(); + try { + $aValue = Helpers::validateNumericNullBool($aValue); + if (is_bool($style)) { + $style = $style ? 0 : 4; + } + $style = Helpers::validateNumericNullSubstitution($style, null); + } catch (Exception $e) { + return $e->getMessage(); } return self::calculateRoman((int) $aValue, (int) $style); } - - /** - * Many functions accept null/false/true argument treated as 0/0/1. - * - * @param mixed $number - */ - private static function nullFalseTrueToNumber(&$number): void - { - $number = Functions::flattenSingleValue($number); - if ($number === null) { - $number = 0; - } elseif (is_bool($number)) { - $number = (int) $number; - } - } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Round.php b/src/PhpSpreadsheet/Calculation/MathTrig/Round.php index 339f0e27..bc1c6669 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Round.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Round.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class Round { @@ -19,12 +18,13 @@ class Round */ public static function builtinROUND($number, $precision) { - MathTrig::nullFalseTrueToNumber($number); - - if (!is_numeric($number) || !is_numeric($precision)) { - return Functions::VALUE(); + try { + $number = Helpers::validateNumericNullBool($number); + $precision = Helpers::validateNumericNullBool($precision); + } catch (Exception $e) { + return $e->getMessage(); } - return round($number, $precision); + return round($number, (int) $precision); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/RoundDown.php b/src/PhpSpreadsheet/Calculation/MathTrig/RoundDown.php index ff1f9bcb..bf19d5d5 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/RoundDown.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/RoundDown.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class RoundDown { @@ -19,21 +18,21 @@ class RoundDown */ public static function funcRoundDown($number, $digits) { - MathTrig::nullFalseTrueToNumber($number); - $digits = Functions::flattenSingleValue($digits); - - if ((is_numeric($number)) && (is_numeric($digits))) { - if ($number == 0.0) { - return 0.0; - } - - if ($number < 0.0) { - return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); - } - - return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); + try { + $number = Helpers::validateNumericNullBool($number); + $digits = Helpers::validateNumericNullSubstitution($digits, null); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if ($number == 0.0) { + return 0.0; + } + + if ($number < 0.0) { + return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); + } + + return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/RoundUp.php b/src/PhpSpreadsheet/Calculation/MathTrig/RoundUp.php index c9507464..a4f00cd3 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/RoundUp.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/RoundUp.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class RoundUp { @@ -19,21 +18,21 @@ class RoundUp */ public static function funcRoundUp($number, $digits) { - MathTrig::nullFalseTrueToNumber($number); - $digits = Functions::flattenSingleValue($digits); - - if ((is_numeric($number)) && (is_numeric($digits))) { - if ($number == 0.0) { - return 0.0; - } - - if ($number < 0.0) { - return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); - } - - return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); + try { + $number = Helpers::validateNumericNullBool($number); + $digits = Helpers::validateNumericNullSubstitution($digits, null); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if ($number == 0.0) { + return 0.0; + } + + if ($number < 0.0) { + return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); + } + + return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN); } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sec.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sec.php new file mode 100644 index 00000000..9bb5a1b7 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sec.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(1.0, cos($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sech.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sech.php new file mode 100644 index 00000000..191bea4d --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sech.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(1.0, cosh($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sign.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sign.php new file mode 100644 index 00000000..84ff523f --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sign.php @@ -0,0 +1,29 @@ +getMessage(); + } + + return Helpers::returnSign($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sin.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sin.php new file mode 100644 index 00000000..f718451c --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sin.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return sin($angle); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sinh.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sinh.php new file mode 100644 index 00000000..ce3ef3e5 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sinh.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return sinh($angle); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Tan.php b/src/PhpSpreadsheet/Calculation/MathTrig/Tan.php new file mode 100644 index 00000000..82612cb8 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Tan.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::verySmallDenominator(sin($angle), cos($angle)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Tanh.php b/src/PhpSpreadsheet/Calculation/MathTrig/Tanh.php new file mode 100644 index 00000000..29bf82e1 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Tanh.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return tanh($angle); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php b/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php index 8cb14d2a..ba82a000 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php @@ -2,8 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use Exception; class Trunc { @@ -19,13 +18,13 @@ class Trunc */ public static function funcTrunc($value = 0, $digits = 0) { - MathTrig::nullFalseTrueToNumber($value); - $digits = Functions::flattenSingleValue($digits); - - // Validate parameters - if ((!is_numeric($value)) || (!is_numeric($digits))) { - return Functions::VALUE(); + try { + $value = Helpers::validateNumericNullBool($value); + $digits = Helpers::validateNumericNullSubstitution($digits, null); + } catch (Exception $e) { + return $e->getMessage(); } + $digits = floor($digits); // Truncate diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php index 825626da..9dd6a49d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php @@ -12,19 +12,16 @@ class AcosTest extends TestCase * @dataProvider providerAcos * * @param mixed $expectedResult - * @param mixed $val */ - public function testAcos($expectedResult, $val = null): void + public function testAcos($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ACOS()'; - } else { - $formula = "=ACOS($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->getCell('A2')->setValue(0.5); + $sheet->getCell('A1')->setValue("=ACOS($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php index bda64d03..d596cc9e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php @@ -12,19 +12,16 @@ class AcoshTest extends TestCase * @dataProvider providerAcosh * * @param mixed $expectedResult - * @param mixed $val */ - public function testAcosh($expectedResult, $val = null): void + public function testAcosh($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ACOSH()'; - } else { - $formula = "=ACOSH($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->getCell('A2')->setValue('1.5'); + $sheet->getCell('A1')->setValue("=ACOSH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php index d81c3b9d..99694215 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class AcotTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerACOT * @@ -21,8 +16,18 @@ class AcotTest extends TestCase */ public function testACOT($expectedResult, $number): void { - $result = MathTrig::ACOT($number); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5); + $sheet->getCell('A1')->setValue("=ACOT($number)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerACOT() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php index 0a3864cc..1d565e73 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class AcothTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerACOTH * @@ -21,8 +16,18 @@ class AcothTest extends TestCase */ public function testACOTH($expectedResult, $number): void { - $result = MathTrig::ACOTH($number); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -10); + $sheet->getCell('A1')->setValue("=ACOTH($number)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerACOTH() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php index 1edc1c33..c1c836f3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php @@ -12,19 +12,16 @@ class AsinTest extends TestCase * @dataProvider providerAsin * * @param mixed $expectedResult - * @param mixed $val */ - public function testAsin($expectedResult, $val = null): void + public function testAsin($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ASIN()'; - } else { - $formula = "=ASIN($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->getCell('A2')->setValue(0.5); + $sheet->getCell('A1')->setValue("=ASIN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php index 1621eb79..ebbb74f1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php @@ -12,19 +12,16 @@ class AsinhTest extends TestCase * @dataProvider providerAsinh * * @param mixed $expectedResult - * @param mixed $val */ - public function testAsinh($expectedResult, $val = null): void + public function testAsinh($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ASINH()'; - } else { - $formula = "=ASINH($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->getCell('A2')->setValue(0.5); + $sheet->getCell('A1')->setValue("=ASINH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php index 4edec4cb..35a96aea 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php @@ -2,28 +2,29 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Atan2Test extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerATAN2 * * @param mixed $expectedResult - * @param mixed $x - * @param mixed $y */ - public function testATAN2($expectedResult, $x, $y): void + public function testATAN2($expectedResult, string $formula): void { - $result = MathTrig::ATAN2($x, $y); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A2')->setValue(5); + $sheet->getCell('A3')->setValue(6); + $sheet->getCell('A1')->setValue("=ATAN2($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerATAN2() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php index 50d76967..4dec2dca 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php @@ -12,19 +12,16 @@ class AtanTest extends TestCase * @dataProvider providerAtan * * @param mixed $expectedResult - * @param mixed $val */ - public function testAtan($expectedResult, $val = null): void + public function testAtan($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ATAN()'; - } else { - $formula = "=ATAN($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->getCell('A2')->setValue(5); + $sheet->getCell('A1')->setValue("=ATAN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php index 2863a182..cc8a243f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php @@ -12,19 +12,16 @@ class AtanhTest extends TestCase * @dataProvider providerAtanh * * @param mixed $expectedResult - * @param mixed $val */ - public function testAtan($expectedResult, $val = null): void + public function testAtanh($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=ATANH()'; - } else { - $formula = "=ATANH($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->getCell('A2')->setValue(0.8); + $sheet->getCell('A1')->setValue("=ATANH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php index da7a9a15..d5ada718 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php @@ -12,19 +12,16 @@ class CosTest extends TestCase * @dataProvider providerCos * * @param mixed $expectedResult - * @param mixed $val */ - public function testCos($expectedResult, $val = null): void + public function testCos($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=COS()'; - } else { - $formula = "=COS($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 2); + $sheet->getCell('A1')->setValue("=COS($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php index 2c452bd5..81dc9c75 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php @@ -12,19 +12,16 @@ class CoshTest extends TestCase * @dataProvider providerCosh * * @param mixed $expectedResult - * @param mixed $val */ - public function testCosh($expectedResult, $val = null): void + public function testCosh($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=COSH()'; - } else { - $formula = "=COSH($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 2); + $sheet->getCell('A1')->setValue("=COSH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php index 3fee6901..cb009a89 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class CotTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerCOT * @@ -21,8 +16,18 @@ class CotTest extends TestCase */ public function testCOT($expectedResult, $angle): void { - $result = MathTrig::COT($angle); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=COT($angle)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerCOT() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php index e3db23d5..e4b42a4d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class CothTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerCOTH * @@ -21,8 +16,18 @@ class CothTest extends TestCase */ public function testCOTH($expectedResult, $angle): void { - $result = MathTrig::COTH($angle); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=COTH($angle)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerCOTH() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php index 675ebf57..8ae48cde 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class CscTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerCSC * @@ -21,8 +16,18 @@ class CscTest extends TestCase */ public function testCSC($expectedResult, $angle): void { - $result = MathTrig::CSC($angle); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=CSC($angle)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerCSC() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php index c630be2f..4a7dbc05 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class CschTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerCSCH * @@ -21,8 +16,18 @@ class CschTest extends TestCase */ public function testCSCH($expectedResult, $angle): void { - $result = MathTrig::CSCH($angle); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=CSCH($angle)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerCSCH() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php index 96c0b046..080925b1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class EvenTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerEVEN * @@ -21,8 +16,14 @@ class EvenTest extends TestCase */ public function testEVEN($expectedResult, $value): void { - $result = MathTrig::EVEN($value); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue("=EVEN($value)"); + $sheet->getCell('A2')->setValue(3.7); + self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerEVEN() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php index d8b55e7c..45c558cd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php @@ -16,15 +16,47 @@ class MovedFunctionsTest extends TestCase { public function testMovedFunctions(): void { + self::assertEqualsWithDelta(0, MathTrig::builtinACOS(1), 1E-9); + self::assertEqualsWithDelta(0, MathTrig::builtinACOSH(1), 1E-9); + self::assertEqualsWithDelta(3.04192400109863, MathTrig::ACOT(-10), 1E-9); + self::assertEqualsWithDelta(-0.20273255405408, MathTrig::ACOTH(-5), 1E-9); + self::assertEqualsWithDelta(0, MathTrig::builtinASIN(0), 1E-9); + self::assertEqualsWithDelta(0, MathTrig::builtinASINH(0), 1E-9); + self::assertEqualsWithDelta(0, MathTrig::builtinATAN(0), 1E-9); + self::assertEqualsWithDelta(0, MathTrig::builtinATANH(0), 1E-9); + self::assertEqualsWithDelta('#DIV/0!', MathTrig::ATAN2(0, 0), 1E-9); self::assertEquals(-6, MathTrig::CEILING(-4.5, -2)); + self::assertEquals(1, MathTrig::builtinCOS(0)); + self::assertEquals(1, MathTrig::builtinCOSH(0)); + self::assertEquals('#DIV/0!', MathTrig::COT(0)); + self::assertEquals('#DIV/0!', MathTrig::COTH(0)); + self::assertEquals('#DIV/0!', MathTrig::CSC(0)); + self::assertEquals('#DIV/0!', MathTrig::CSCH(0)); + self::assertEquals(6, MathTrig::EVEN(4.5)); self::assertEquals(-6, MathTrig::FLOOR(-4.5, 2)); self::assertEquals(0.23, MathTrig::FLOORMATH(0.234, 0.01)); self::assertEquals(-4, MathTrig::FLOORPRECISE(-2.5, 2)); self::assertEquals(-9, MathTrig::INT(-8.3)); self::assertEquals(6, MathTrig::MROUND(7.3, 3)); + self::assertEquals(5, MathTrig::ODD(4.5)); self::assertEquals(3.3, MathTrig::builtinROUND(3.27, 1)); self::assertEquals(662, MathTrig::ROUNDDOWN(662.79, 0)); self::assertEquals(663, MathTrig::ROUNDUP(662.79, 0)); + self::assertEquals(1, MathTrig::SEC(0)); + self::assertEquals(1, MathTrig::SECH(0)); + self::assertEquals(1, MathTrig::SIGN(79.2)); + self::assertEquals(0, MathTrig::builtinSIN(0)); + self::assertEquals(0, MathTrig::builtinSINH(0)); + self::assertEquals(0, MathTrig::builtinTAN(0)); + self::assertEquals(0, MathTrig::builtinTANH(0)); self::assertEquals(70, MathTrig::TRUNC(79.2, -1)); + self::assertEquals(1, MathTrig::returnSign(79.2)); + self::assertEquals(80, MathTrig::getEven(79.2)); + $nullVal = null; + MathTrig::nullFalseTrueToNumber($nullVal); + self::assertSame(0, $nullVal); + $nullVal = true; + MathTrig::nullFalseTrueToNumber($nullVal); + self::assertSame(1, $nullVal); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php index 6c5758c6..ed262d9c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class OddTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerODD * @@ -21,8 +16,14 @@ class OddTest extends TestCase */ public function testODD($expectedResult, $value): void { - $result = MathTrig::ODD($value); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->getCell('A1')->setValue("=ODD($value)"); + $sheet->getCell('A2')->setValue(3.7); + self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerODD() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php index ad4b196c..a47ae7b5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class SecTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSEC * @@ -21,8 +16,18 @@ class SecTest extends TestCase */ public function testSEC($expectedResult, $angle): void { - $result = MathTrig::SEC($angle); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=SEC($angle)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerSEC() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php index b9488bda..65ed7b73 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class SechTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSECH * @@ -21,8 +16,18 @@ class SechTest extends TestCase */ public function testSECH($expectedResult, $angle): void { - $result = MathTrig::SECH($angle); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 2.7); + $sheet->setCellValue('A4', -3.8); + $sheet->setCellValue('A5', -5.2); + $sheet->getCell('A1')->setValue("=SECH($angle)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerSECH() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php index 68f5acb9..a4311219 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php @@ -2,17 +2,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class SignTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSIGN * @@ -21,8 +16,17 @@ class SignTest extends TestCase */ public function testSIGN($expectedResult, $value): void { - $result = MathTrig::SIGN($value); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 1.3); + $sheet->setCellValue('A3', 0); + $sheet->setCellValue('A4', -3.8); + $sheet->getCell('A1')->setValue("=SIGN($value)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); } public function providerSIGN() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php index 7a144e0e..e9ad6329 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php @@ -12,19 +12,16 @@ class SinTest extends TestCase * @dataProvider providerSin * * @param mixed $expectedResult - * @param mixed $val */ - public function testSin($expectedResult, $val = null): void + public function testSin($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=SIN()'; - } else { - $formula = "=SIN($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 2); + $sheet->getCell('A1')->setValue("=SIN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php index c24bb192..38bfc7ef 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php @@ -12,19 +12,16 @@ class SinhTest extends TestCase * @dataProvider providerCosh * * @param mixed $expectedResult - * @param mixed $val */ - public function testSinh($expectedResult, $val = null): void + public function testSinh($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=SINH()'; - } else { - $formula = "=SINH($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 2); + $sheet->getCell('A1')->setValue("=SINH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php index 13093f6a..5a482cd8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php @@ -12,19 +12,16 @@ class TanTest extends TestCase * @dataProvider providerTan * * @param mixed $expectedResult - * @param mixed $val */ - public function testTan($expectedResult, $val = null): void + public function testTan($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=TAN()'; - } else { - $formula = "=TAN($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 1); + $sheet->getCell('A1')->setValue("=TAN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php index 69f28e8a..5fe50d7c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php @@ -12,19 +12,16 @@ class TanhTest extends TestCase * @dataProvider providerTanh * * @param mixed $expectedResult - * @param mixed $val */ - public function testTanh($expectedResult, $val = null): void + public function testTanh($expectedResult, string $formula): void { - if ($val === null) { + if ($expectedResult === 'exception') { $this->expectException(CalcExp::class); - $formula = '=TANH()'; - } else { - $formula = "=TANH($val)"; } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); + $sheet->setCellValue('A2', 1); + $sheet->getCell('A1')->setValue("=TANH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/data/Calculation/MathTrig/ACOS.php b/tests/data/Calculation/MathTrig/ACOS.php index f592de09..487a0628 100644 --- a/tests/data/Calculation/MathTrig/ACOS.php +++ b/tests/data/Calculation/MathTrig/ACOS.php @@ -1,10 +1,14 @@ Date: Sat, 13 Mar 2021 12:43:16 +0100 Subject: [PATCH 108/187] Add null typehint to Worksheet::getColumnDimension() since it returns null (#1914) * Add null typehint to `Worksheet::getColumnDimension()` since it can return null * `getColumnDimensionByColumn()` and `getRowDimension()` --- src/PhpSpreadsheet/Worksheet/Worksheet.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 19119970..09ce3e61 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -1337,7 +1337,7 @@ class Worksheet implements IComparable * @param int $pRow Numeric index of the row * @param bool $create * - * @return RowDimension + * @return null|RowDimension */ public function getRowDimension($pRow, $create = true) { @@ -1363,7 +1363,7 @@ class Worksheet implements IComparable * @param string $pColumn String index of the column eg: 'A' * @param bool $create * - * @return ColumnDimension + * @return null|ColumnDimension */ public function getColumnDimension($pColumn, $create = true) { @@ -1390,7 +1390,7 @@ class Worksheet implements IComparable * * @param int $columnIndex Numeric column coordinate of the cell * - * @return ColumnDimension + * @return null|ColumnDimension */ public function getColumnDimensionByColumn($columnIndex) { From 0edfc3257f9f2e530e04d8e8b8acd9dd2a2accb4 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Sun, 14 Mar 2021 20:34:23 +0530 Subject: [PATCH 109/187] Update the fopen mode for writer --- src/PhpSpreadsheet/Writer/BaseWriter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpSpreadsheet/Writer/BaseWriter.php b/src/PhpSpreadsheet/Writer/BaseWriter.php index afda5c43..d52b0d4a 100644 --- a/src/PhpSpreadsheet/Writer/BaseWriter.php +++ b/src/PhpSpreadsheet/Writer/BaseWriter.php @@ -108,7 +108,7 @@ abstract class BaseWriter implements IWriter return; } - $fileHandle = $filename ? fopen($filename, 'wb+') : false; + $fileHandle = $filename ? fopen($filename, 'wb') : false; if ($fileHandle === false) { throw new Exception('Could not open file "' . $filename . '" for writing.'); } From 5686453bcce92a31fcbe566c087bf063f0bf9941 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Sun, 14 Mar 2021 20:48:10 +0530 Subject: [PATCH 110/187] Add test case for excel with media --- .../Writer/Xlsx/DrawingsTest.php | 22 ++++++++++++++++++ .../XLSX/saving_drawing_with_same_path.xlsx | Bin 0 -> 11717 bytes 2 files changed, 22 insertions(+) create mode 100644 tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index d6ad77c6..58e3be57 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -42,4 +42,26 @@ class DrawingsTest extends AbstractFunctional // Fake assert. The only thing we need is to ensure the file is loaded without exception self::assertNotNull($reloadedSpreadsheet); } + + /** + * Test save and load XLSX file with drawing with the same file name. + */ + public function testSaveLoadWithDrawingWithSamePath(): void + { + // Read spreadsheet from file + $filePath = 'tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx'; + $reader = new Xlsx(); + $spreadsheet = $reader->load($filePath); + + $spreadsheet->getActiveSheet()->setCellValue('D5', 'foo'); + // Save spreadsheet to file to the same path. Success test case won't + // throw exception here + $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); + $writer->save($filePath); + + $reloadedSpreadsheet = $reader->load($filePath); + + // Fake assert. The only thing we need is to ensure the file is loaded without exception + self::assertNotNull($reloadedSpreadsheet); + } } diff --git a/tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx b/tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..53f9a6b9a46d3a7358770e05e5cd2a6c9e40fa10 GIT binary patch literal 11717 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 HAfNsRwQ3$l literal 0 HcmV?d00001 From 51abdf0b8f7b406bab07e4d954e0e8454a8f1f8f Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Sun, 14 Mar 2021 22:20:11 +0530 Subject: [PATCH 111/187] Refactor xlsx writer * Move file handler creation and file addition to the end --- src/PhpSpreadsheet/Writer/BaseWriter.php | 2 +- src/PhpSpreadsheet/Writer/Xlsx.php | 93 ++++++++++-------- .../Writer/Xlsx/DrawingsTest.php | 1 + .../XLSX/saving_drawing_with_same_path.xlsx | Bin 11717 -> 7936 bytes 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/BaseWriter.php b/src/PhpSpreadsheet/Writer/BaseWriter.php index d52b0d4a..afda5c43 100644 --- a/src/PhpSpreadsheet/Writer/BaseWriter.php +++ b/src/PhpSpreadsheet/Writer/BaseWriter.php @@ -108,7 +108,7 @@ abstract class BaseWriter implements IWriter return; } - $fileHandle = $filename ? fopen($filename, 'wb') : false; + $fileHandle = $filename ? fopen($filename, 'wb+') : false; if ($fileHandle === false) { throw new Exception('Could not open file "' . $filename . '" for writing.'); } diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index d71541c8..10fc50c9 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -182,8 +182,6 @@ class Xlsx extends BaseWriter $this->pathNames = []; $this->spreadSheet->garbageCollect(); - $this->openFileHandle($pFilename); - $saveDebugLog = Calculation::getInstance($this->spreadSheet)->getDebugLog()->getWriteDebugLog(); Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog(false); $saveDateReturnType = Functions::getReturnDateType(); @@ -206,77 +204,72 @@ class Xlsx extends BaseWriter // Create drawing dictionary $this->drawingHashTable->addFromSource($this->getWriterPart('Drawing')->allDrawings($this->spreadSheet)); - $options = new Archive(); - $options->setEnableZip64(false); - $options->setOutputStream($this->fileHandle); - - $this->zip = new ZipStream(null, $options); - + $zipContent = []; // Add [Content_Types].xml to ZIP file - $this->addZipFile('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->spreadSheet, $this->includeCharts)); + $zipContent['[Content_Types].xml'] = $this->getWriterPart('ContentTypes')->writeContentTypes($this->spreadSheet, $this->includeCharts); //if hasMacros, add the vbaProject.bin file, Certificate file(if exists) if ($this->spreadSheet->hasMacros()) { $macrosCode = $this->spreadSheet->getMacrosCode(); if ($macrosCode !== null) { // we have the code ? - $this->addZipFile('xl/vbaProject.bin', $macrosCode); //allways in 'xl', allways named vbaProject.bin + $zipContent['xl/vbaProject.bin'] = $macrosCode; //allways in 'xl', allways named vbaProject.bin if ($this->spreadSheet->hasMacrosCertificate()) { //signed macros ? // Yes : add the certificate file and the related rels file - $this->addZipFile('xl/vbaProjectSignature.bin', $this->spreadSheet->getMacrosCertificate()); - $this->addZipFile('xl/_rels/vbaProject.bin.rels', $this->getWriterPart('RelsVBA')->writeVBARelationships($this->spreadSheet)); + $zipContent['xl/vbaProjectSignature.bin'] = $this->spreadSheet->getMacrosCertificate(); + $zipContent['xl/_rels/vbaProject.bin.rels'] = $this->getWriterPart('RelsVBA')->writeVBARelationships($this->spreadSheet); } } } //a custom UI in this workbook ? add it ("base" xml and additional objects (pictures) and rels) if ($this->spreadSheet->hasRibbon()) { $tmpRibbonTarget = $this->spreadSheet->getRibbonXMLData('target'); - $this->addZipFile($tmpRibbonTarget, $this->spreadSheet->getRibbonXMLData('data')); + $zipContent[$tmpRibbonTarget] = $this->spreadSheet->getRibbonXMLData('data'); if ($this->spreadSheet->hasRibbonBinObjects()) { $tmpRootPath = dirname($tmpRibbonTarget) . '/'; $ribbonBinObjects = $this->spreadSheet->getRibbonBinObjects('data'); //the files to write foreach ($ribbonBinObjects as $aPath => $aContent) { - $this->addZipFile($tmpRootPath . $aPath, $aContent); + $zipContent[$tmpRootPath . $aPath] = $aContent; } //the rels for files - $this->addZipFile($tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels', $this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->spreadSheet)); + $zipContent[$tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels'] = $this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->spreadSheet); } } // Add relationships to ZIP file - $this->addZipFile('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->spreadSheet)); - $this->addZipFile('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->spreadSheet)); + $zipContent['_rels/.rels'] = $this->getWriterPart('Rels')->writeRelationships($this->spreadSheet); + $zipContent['xl/_rels/workbook.xml.rels'] = $this->getWriterPart('Rels')->writeWorkbookRelationships($this->spreadSheet); // Add document properties to ZIP file - $this->addZipFile('docProps/app.xml', $this->getWriterPart('DocProps')->writeDocPropsApp($this->spreadSheet)); - $this->addZipFile('docProps/core.xml', $this->getWriterPart('DocProps')->writeDocPropsCore($this->spreadSheet)); + $zipContent['docProps/app.xml'] = $this->getWriterPart('DocProps')->writeDocPropsApp($this->spreadSheet); + $zipContent['docProps/core.xml'] = $this->getWriterPart('DocProps')->writeDocPropsCore($this->spreadSheet); $customPropertiesPart = $this->getWriterPart('DocProps')->writeDocPropsCustom($this->spreadSheet); if ($customPropertiesPart !== null) { - $this->addZipFile('docProps/custom.xml', $customPropertiesPart); + $zipContent['docProps/custom.xml'] = $customPropertiesPart; } // Add theme to ZIP file - $this->addZipFile('xl/theme/theme1.xml', $this->getWriterPart('Theme')->writeTheme($this->spreadSheet)); + $zipContent['xl/theme/theme1.xml'] = $this->getWriterPart('Theme')->writeTheme($this->spreadSheet); // Add string table to ZIP file - $this->addZipFile('xl/sharedStrings.xml', $this->getWriterPart('StringTable')->writeStringTable($this->stringTable)); + $zipContent['xl/sharedStrings.xml'] = $this->getWriterPart('StringTable')->writeStringTable($this->stringTable); // Add styles to ZIP file - $this->addZipFile('xl/styles.xml', $this->getWriterPart('Style')->writeStyles($this->spreadSheet)); + $zipContent['xl/styles.xml'] = $this->getWriterPart('Style')->writeStyles($this->spreadSheet); // Add workbook to ZIP file - $this->addZipFile('xl/workbook.xml', $this->getWriterPart('Workbook')->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas)); + $zipContent['xl/workbook.xml'] = $this->getWriterPart('Workbook')->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas); $chartCount = 0; // Add worksheets for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { - $this->addZipFile('xl/worksheets/sheet' . ($i + 1) . '.xml', $this->getWriterPart('Worksheet')->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts)); + $zipContent['xl/worksheets/sheet' . ($i + 1) . '.xml'] = $this->getWriterPart('Worksheet')->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts); if ($this->includeCharts) { $charts = $this->spreadSheet->getSheet($i)->getChartCollection(); if (count($charts) > 0) { foreach ($charts as $chart) { - $this->addZipFile('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas)); + $zipContent['xl/charts/chart' . ($chartCount + 1) . '.xml'] = $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas); ++$chartCount; } } @@ -287,19 +280,19 @@ class Xlsx extends BaseWriter // Add worksheet relationships (drawings, ...) for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { // Add relationships - $this->addZipFile('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts)); + $zipContent['xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels'] = $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts); // Add unparsedLoadedData $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName(); $unparsedLoadedData = $this->spreadSheet->getUnparsedLoadedData(); if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'])) { foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['ctrlProps'] as $ctrlProp) { - $this->addZipFile($ctrlProp['filePath'], $ctrlProp['content']); + $zipContent[$ctrlProp['filePath']] = $ctrlProp['content']; } } if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'])) { foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['printerSettings'] as $ctrlProp) { - $this->addZipFile($ctrlProp['filePath'], $ctrlProp['content']); + $zipContent[$ctrlProp['filePath']] = $ctrlProp['content']; } } @@ -312,13 +305,13 @@ class Xlsx extends BaseWriter // Add drawing and image relationship parts if (($drawingCount > 0) || ($chartCount > 0)) { // Drawing relationships - $this->addZipFile('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts)); + $zipContent['xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels'] = $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts); // Drawings - $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); + $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts); } elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) { // Drawings - $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); + $zipContent['xl/drawings/drawing' . ($i + 1) . '.xml'] = $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts); } // Add unparsed drawings @@ -327,7 +320,7 @@ class Xlsx extends BaseWriter $drawingFile = array_search($relId, $unparsedLoadedData['sheets'][$sheetCodeName]['drawingOriginalIds']); if ($drawingFile !== false) { $drawingFile = ltrim($drawingFile, '.'); - $this->addZipFile('xl' . $drawingFile, $drawingXml); + $zipContent['xl' . $drawingFile] = $drawingXml; } } } @@ -335,30 +328,30 @@ class Xlsx extends BaseWriter // Add comment relationship parts if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) { // VML Comments - $this->addZipFile('xl/drawings/vmlDrawing' . ($i + 1) . '.vml', $this->getWriterPart('Comments')->writeVMLComments($this->spreadSheet->getSheet($i))); + $zipContent['xl/drawings/vmlDrawing' . ($i + 1) . '.vml'] = $this->getWriterPart('Comments')->writeVMLComments($this->spreadSheet->getSheet($i)); // Comments - $this->addZipFile('xl/comments' . ($i + 1) . '.xml', $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i))); + $zipContent['xl/comments' . ($i + 1) . '.xml'] = $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i)); } // Add unparsed relationship parts if (isset($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'])) { foreach ($unparsedLoadedData['sheets'][$sheetCodeName]['vmlDrawings'] as $vmlDrawing) { - $this->addZipFile($vmlDrawing['filePath'], $vmlDrawing['content']); + $zipContent[$vmlDrawing['filePath']] = $vmlDrawing['content']; } } // Add header/footer relationship parts if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) { // VML Drawings - $this->addZipFile('xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml', $this->getWriterPart('Drawing')->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i))); + $zipContent['xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml'] = $this->getWriterPart('Drawing')->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i)); // VML Drawing relationships - $this->addZipFile('xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels', $this->getWriterPart('Rels')->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i))); + $zipContent['xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels'] = $this->getWriterPart('Rels')->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i)); // Media foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) { - $this->addZipFile('xl/media/' . $image->getIndexedFilename(), file_get_contents($image->getPath())); + $zipContent['xl/media/' . $image->getIndexedFilename()] = file_get_contents($image->getPath()); } } } @@ -381,7 +374,7 @@ class Xlsx extends BaseWriter $imageContents = file_get_contents($imagePath); } - $this->addZipFile('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); + $zipContent['xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())] = $imageContents; } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof MemoryDrawing) { ob_start(); call_user_func( @@ -391,13 +384,23 @@ class Xlsx extends BaseWriter $imageContents = ob_get_contents(); ob_end_clean(); - $this->addZipFile('xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); + $zipContent['xl/media/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())] = $imageContents; } } Functions::setReturnDateType($saveDateReturnType); Calculation::getInstance($this->spreadSheet)->getDebugLog()->setWriteDebugLog($saveDebugLog); + $this->openFileHandle($pFilename); + + $options = new Archive(); + $options->setEnableZip64(false); + $options->setOutputStream($this->fileHandle); + + $this->zip = new ZipStream(null, $options); + + $this->addZipFiles($zipContent); + // Close file try { $this->zip->finish(); @@ -545,4 +548,12 @@ class Xlsx extends BaseWriter $this->zip->addFile($path, $content); } } + + private function addZipFiles(array $zipContent): void + { + foreach ($zipContent as $path => $content) + { + $this->addZipFile($path, $content); + } + } } diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index 58e3be57..0880bde9 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; +use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Settings; use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; diff --git a/tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx b/tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx index 53f9a6b9a46d3a7358770e05e5cd2a6c9e40fa10..a88d43d3dc71f029d530ce805b217e50183b414f 100644 GIT binary patch delta 2615 zcmZ{m2UJs67{^}-fr>N7OaBEC?JA$^d@*pcx{vO?mH*%`+eWL-@X6)Pix>wdvkAh zq_i>wL7zYtX>^kA@?K0F0)j4}AV>-P8tBBJv#E4;h|jTDDl6C|J|?=dAHhO=Dha99 zSXfSgV0S49S`Y3aOlmaC)I>C9^Cs0LLsN7s{6wL3AXE*4zQ(KbZSa#uk|F(_(l64$ zE7%|*2n|BR7>B%>j98W_B{o)Ee+qdDVJu0Qs5SAJfWQC(BS{=$FsWjs3&lp5N+PW6 z`w`E>X(>#EPIWsbL4$%t(4T zOGIILyX9KU(9p~s?UzIJSDM<93Fs5a_L^0J>Jc0oXWN_OV{y2&Ki_?7I_>GgkCjco zhH|yNpSSc|^H|cr<>qf)@MGE@TTZwYDcanMD!;}p+tP7(5=BhUXZGyz8;#O8unK6M za}HkLN(|S2upU3Km|~?bBaBOkVdwI0KGcf$Y!1wGwhfqFaxMFA7P)qDM?)?RFM~cs zNJEhP$M8WSJT>P5{TnlM+UrEQ2Y;pA%O+K0&^xm$H!1vq*e2P8py?@-GLYmI zSV6^=Bu5!c+Cc_`Chpp(Y&l}hk}HvaXf^;VQz;8UI0)j8U^a1iz5~q1X6VEja>QHw z2IEL|nfq04k=ywS`6+})EdhtH{*(K*3z8Dab10>`CVsW+@S~QUwEGG z=FuJ3gzsc$UOhm%S4^qtaQpea&DKHEa~JtpU2^`sqwSWqo0re|1dfz+I9g}ik>4W} zymz*o4Q%P-^mY9C$BwOgH=lBxYB-WnyLj=nG*K|HLFm9!RxC-g?#33A%(yU~w-)BwNV|K02Eo?%S{NR%{UH6rBABBOdu->V7 z8}aHXtIOf1y}4}{3K?}{-4)HoJAB{BOg>J1>IpFB1ZtDlSP{w#H{FmQ>y zaDK|=y94%y`za-ydF>9v8f!w>)S&hw`|cw5Mx~HuQ@WqB;em5qUUy&X9lREG{Wj#kG$V2D*q(mePSao?m9i%}cfywyKVuYS6a4Qve&c-P!y74kjy`@n~n2?=Z&>hk?;y;m(((<@ZKsg=lOkJu#B$kpY&G|po zd!5ZrAx~_-@V-;$*}n3swig?EEj#gAH^M!Ghy1(0ulH#D^5RZAt0DZ1TGEg;o7dw` z3(hJFt@3K~vp^8WZ-i{vq2u;d`{0=u7~zM33GP}MTkQ_TR|4f30u|~2LEX~Q<|R)mchgfba@{|3{KCZBsiTW7b+tHUc92wYVR0PAcQz?8adUF+>EzUfcg>^`4Q9y zPgXn_=8-F)xOA12$T1_~rQnXaLTG|pFX#u{KjAdoJy+=r{_lFqVDqh=7~DEn;|;+H z{~tyQPXM>k)dVWQmEfkz6}bvL1>DJ2Q}ljJ@sF>;QMiAtqRYU}Ky^ts1F+$mZ2>d0 z6!+&rQHY*tDB zwljas{#p*80apsim#XPtF9;xCPgxULuaGc)0Kqek0DzgbOblLt7cgSOu;c;&{;wDq z7-iEx(BlRG5q222z(6HVh%&f& z4k28Syd8IV`V%0gFwnx@KtZ3N*tc*GppZD)qGnkz>+ zBFvW=4)!0ciL4h#;V=%}r7#m9G=M_h8xTOAWhe(A=fuR^>td`CIR{g8emjUMgDAo{ z-@L$1kp~R`0?ZvS#&)iD!H^SXf`P>oexJv6a93;6J*?6!C@56+>rh=#o0{0 zBsp8Wu?gAu8($vbP(qnv2dL)3_p4(3YCRMvd9Ess;!^qFX?b*Rc%W4p33-Zhc@-q zo+L*@s_RpVrc4P~E}=p>{?4NM#=2WKxyvQ(uGOMc^VjdnoQ}5`5|U94ctfkWVV3+$ z$l>6Kk7u5GwTXET8j-1#)e7%YiR+3e5uYzRM0|nn_uZ=4V_BvQ1cSd(pqo+M()IQ} z;$S2STeD5z%f%#M>eKIOQL6}+NM52^SAH54>TpmKEJ3(P!v&T--ou~@DFMa1tE)B6 z2yf@43FRin_50BGhQc0x%?o{ZqL{lEaW8S$+RAZQ*zph{iYrZ$d##8JqC!R_c2W#` z8?bwhZiwREoDc`{;4;OuT>4-xNM8O!4VyPYo5KXYRg3xkL+D$wQ@u%~U{32N1o~Ys z0%!BugW?wIw{}Oj^`nnlFjUNsWv@cFUi^BlI3FLfx)8Po@w600S+4 za=2+gcMy)4E~EIoCX1l&YsxYjY9IU3#Pyhy9@zYt!TJ5wQvy56ynjxRjUr zLQFJCaj4qL`+1_kXs~3a$#{C_c9C_P&eHfYWQA+dA+%RnIb&sKdTrZiLWhp(M(XyS zpeOO1-uX!8301Lzh{Z#r36eK#6{-(}&H$goV@Z$ukvx3dIQ01Z*w8})fFyvX522*M zrACM&4%XBzEs^^7KYK?AC+L3S<@RVV*2%O;wA!An)l!qLlebFAvcQc%PAD5Xj zsk_U;b*Jq6vsT^j`o!udSJw)hKlRzB726%cxHoFu zf}dQGDOs6uac7K)+F)gK(qwmO%W9C8R34M<=a7dAviQrd@TmVP9n&)N;tQFkO`8s5 zV&dL;6dcWOzwEMBTf-Akw<$@=(Z)jXeZs@jXxxYM1?6kr7|RW#8INe_J-53J@#Yt0 zht_+dbIpFHzjl~h9WiXV-499bo$N)4DhU}EOzi&~?fGC(tOwC_e3Mq%I1H0XLWA%SCV(U0S|l@?P_n(s3_=j@)um4WFtrwpp#GFGt3k zY_KZVtjzC@+yK^KGA}t*+qS3TTp#)E)A zhqzcb?HGl03RyE{T{GyO9o1{v4I+H>d$I##{y4qjlXTHup|tyB*YJkEcfUl0F*F+q z{MCtqxC_spZ8VCN*VgISpLkRJYQ--}y#%fEvX~+Y@j&S@yU-Lmg~eyX*T-VLpV*Ds8$3VosoA=`*4 zElrmqRt14>!4c&d5M6lb!k~t;po;QJOBe1|Ynvu5k!8;eO3FP`a|^A-2s!>Dwiile ziF;G!k|xcnabpu<7Ruu4X857-tf`NKp%W&xHIhnWm$*%FCWA5Q!v`ZHbE47@<6g*f zTh#1~9v#uT+?G-m(%ft7CJ6GGTyZ2H5I<3RL|n zkAFw?w0KBpD7Xd-4;-)@Tcs!cLbTp^{Pnu~+t$R5`qf2eXgKiY@Z-DwAXH|(hbyVD|(%X=GU?)IhB7#eldvP@neQ(AZ zaPS+a5zWM8WgfdUht)mH3Zsnyz-bnA5wSm4*byw}BC`u}SlY9!FggK2-zg)uuQFxYOSp&`qO8p;D^-P{1%LVLu92WL0D~!%($Ax4*CsP)SH4B|xio=?oWrbYP zv2=p0=nuJpT`s^tu!3h<1I`{Q)g0-0_KO1jZP}$bEa_QR7@f{UoG0-AQQxzlAEwJL zeBh~{Wrfjsd@x;5^LvHE68Q59(|l-l-2w|ImK8=H5`gl7GZ_Vb-1fzjrN9jt*^ z)__|rIOA`&<~LJXSx?m#>?hx0!_zR+*uB$$^Jjv8ZCIQ_v*M0j+Q1r#Wrfi-OypU` z1ak0*jpcY4W4=q~W}<+|j7vC`N{~0eMGD+pTstQ2zpHWVq5~dSSXLOFB?8dfW&fY0 zC>%B808W()GaQsym&QJHL30p`C{P%E1x0_0lD7QXyIDcDNQ%HK=ie0j(Hn5<>38KM ztbR1A*oUpT1mnc$cnN7H;6FV6`=?NXXEc^I;6f$nIC0S*X2?Ed&22l^CFp6gVjMGM z-3j}E1 Date: Sun, 14 Mar 2021 22:25:13 +0530 Subject: [PATCH 112/187] Update PHPCS changes --- src/PhpSpreadsheet/Writer/Xlsx.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index 10fc50c9..23354f8c 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -551,8 +551,7 @@ class Xlsx extends BaseWriter private function addZipFiles(array $zipContent): void { - foreach ($zipContent as $path => $content) - { + foreach ($zipContent as $path => $content) { $this->addZipFile($path, $content); } } From ed62526acad6dc0d8da3a5f14e27d207379ce1e3 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 14 Mar 2021 19:58:10 +0100 Subject: [PATCH 113/187] First step extracting INDIRECT() and OFFSET() to their own classes (#1921) * First step extracting INDIRECT() and OFFSET() to their own classes * Start building unit tests for OFFSET() and INDEX() * Named ranges should be handled by the Calculation Engine, not by the implementation of the Excel INDIRECT() function * When calling the calculation engine to get the range of cells to return, INDIRECT() and OFFSET() should use the instance of the calculation engine for the current workbook to benefit from cached results in that range There's a couple of minor bugfixes in here; but it's basically just refactoring of the INDIRECT() and OFFSET() Excel functions into their own classes - still needs a lot of work on unit testing; and there's a lot more that could be improved in the code itself (including handling of the a1 flag for R1C1 format in INDIRECT() --- samples/Calculations/LookupRef/INDIRECT.php | 33 ++++ samples/Calculations/LookupRef/OFFSET.php | 33 ++++ .../Calculation/Calculation.php | 6 +- src/PhpSpreadsheet/Calculation/LookupRef.php | 153 ++++-------------- .../Calculation/LookupRef/Indirect.php | 75 +++++++++ .../Calculation/LookupRef/Offset.php | 136 ++++++++++++++++ .../Functions/LookupRef/IndirectTest.php | 55 +++++++ .../Functions/LookupRef/OffsetTest.php | 32 ++++ tests/data/Calculation/LookupRef/INDIRECT.php | 16 ++ tests/data/Calculation/LookupRef/OFFSET.php | 8 + 10 files changed, 426 insertions(+), 121 deletions(-) create mode 100644 samples/Calculations/LookupRef/INDIRECT.php create mode 100644 samples/Calculations/LookupRef/OFFSET.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php create mode 100644 src/PhpSpreadsheet/Calculation/LookupRef/Offset.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php create mode 100644 tests/data/Calculation/LookupRef/INDIRECT.php create mode 100644 tests/data/Calculation/LookupRef/OFFSET.php diff --git a/samples/Calculations/LookupRef/INDIRECT.php b/samples/Calculations/LookupRef/INDIRECT.php new file mode 100644 index 00000000..ffbada9a --- /dev/null +++ b/samples/Calculations/LookupRef/INDIRECT.php @@ -0,0 +1,33 @@ +log('Returns the cell specified by a text string.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$data = [ + [8, 9, 0], + [3, 4, 5], + [9, 1, 3], + [4, 6, 2], +]; +$worksheet->fromArray($data, null, 'C1'); + +$spreadsheet->addNamedRange(new NamedRange('NAMED_RANGE_FOR_CELL_D4', $worksheet, '="$D$4"')); + +$worksheet->getCell('A1')->setValue('=INDIRECT("C1")'); +$worksheet->getCell('A2')->setValue('=INDIRECT("D"&4)'); +$worksheet->getCell('A3')->setValue('=INDIRECT("E"&ROW())'); +$worksheet->getCell('A4')->setValue('=SUM(INDIRECT("$C$4:$E$4"))'); +$worksheet->getCell('A5')->setValue('=INDIRECT(NAMED_RANGE_FOR_CELL_D4)'); + +for ($row = 1; $row <= 5; ++$row) { + $cell = $worksheet->getCell("A{$row}"); + $helper->log("A{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/samples/Calculations/LookupRef/OFFSET.php b/samples/Calculations/LookupRef/OFFSET.php new file mode 100644 index 00000000..ae613ec5 --- /dev/null +++ b/samples/Calculations/LookupRef/OFFSET.php @@ -0,0 +1,33 @@ +log('Returns a cell range that is a specified number of rows and columns from a cell or range of cells.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +$data = [ + [null, 'Week 1', 'Week 2', 'Week 3', 'Week 4'], + ['Sunday', 4500, 2200, 3800, 1500], + ['Monday', 5500, 6100, 5200, 4800], + ['Tuesday', 7000, 6200, 5000, 7100], + ['Wednesday', 8000, 4000, 3900, 7600], + ['Thursday', 5900, 5500, 6900, 7100], + ['Friday', 4900, 6300, 6900, 5200], + ['Saturday', 3500, 3900, 5100, 4100], +]; +$worksheet->fromArray($data, null, 'A3'); + +$worksheet->getCell('H1')->setValue('=OFFSET(A3, 3, 1)'); +$worksheet->getCell('H2')->setValue('=SUM(OFFSET(A3, 3, 1, 1, 4))'); +$worksheet->getCell('H3')->setValue('=SUM(OFFSET(B3:E3, 3, 0))'); +$worksheet->getCell('H4')->setValue('=SUM(OFFSET(E3, 1, -3, 7))'); + +for ($row = 1; $row <= 4; ++$row) { + $cell = $worksheet->getCell("H{$row}"); + $helper->log("H{$row}: {$cell->getValue()} => {$cell->getCalculatedValue()}"); +} diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 1db4722b..c88eff31 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1408,7 +1408,7 @@ class Calculation ], 'INDIRECT' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'INDIRECT'], + 'functionCall' => [LookupRef\Indirect::class, 'INDIRECT'], 'argumentCount' => '1,2', 'passCellReference' => true, ], @@ -1881,7 +1881,7 @@ class Calculation ], 'OFFSET' => [ 'category' => Category::CATEGORY_LOOKUP_AND_REFERENCE, - 'functionCall' => [LookupRef::class, 'OFFSET'], + 'functionCall' => [LookupRef\Offset::class, 'OFFSET'], 'argumentCount' => '3-5', 'passCellReference' => true, 'passByReference' => [true], @@ -2702,7 +2702,7 @@ class Calculation * Get an instance of this class. * * @param ?Spreadsheet $spreadsheet Injected spreadsheet for working with a PhpSpreadsheet Spreadsheet object, - * or NULL to create a standalone claculation engine + * or NULL to create a standalone calculation engine */ public static function getInstance(?Spreadsheet $spreadsheet = null): self { diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index d2cc4f94..17115a06 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -4,12 +4,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Address; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\HLookup; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Indirect; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Lookup; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Matrix; +use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\Offset; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\RowColumnInformation; use PhpOffice\PhpSpreadsheet\Calculation\LookupRef\VLookup; use PhpOffice\PhpSpreadsheet\Cell\Cell; -use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; class LookupRef @@ -181,56 +182,22 @@ class LookupRef * Excel Function: * =INDIRECT(cellAddress) * + * @Deprecated 1.18.0 + * + * @see Use the INDIRECT() method in the LookupRef\Indirect class instead + * * NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010 * * @param null|array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula) * @param Cell $pCell The current cell (containing this formula) * - * @return mixed The cells referenced by cellAddress + * @return array|string An array containing a cell or range of cells, or a string on error * * @TODO Support for the optional a1 parameter introduced in Excel 2010 */ public static function INDIRECT($cellAddress = null, ?Cell $pCell = null) { - $cellAddress = Functions::flattenSingleValue($cellAddress); - if ($cellAddress === null || $cellAddress === '') { - return Functions::REF(); - } - - $cellAddress1 = $cellAddress; - $cellAddress2 = null; - if (strpos($cellAddress, ':') !== false) { - [$cellAddress1, $cellAddress2] = explode(':', $cellAddress); - } - - if ( - (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress1, $matches)) || - (($cellAddress2 !== null) && (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $cellAddress2, $matches))) - ) { - if (!preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $cellAddress1, $matches)) { - return Functions::REF(); - } - - if (strpos($cellAddress, '!') !== false) { - [$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - $sheetName = trim($sheetName, "'"); - $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName); - } else { - $pSheet = $pCell->getWorksheet(); - } - - return Calculation::getInstance()->extractNamedRange($cellAddress, $pSheet, false); - } - - if (strpos($cellAddress, '!') !== false) { - [$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - $sheetName = trim($sheetName, "'"); - $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName); - } else { - $pSheet = $pCell->getWorksheet(); - } - - return Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false); + return Indirect::INDIRECT($cellAddress, $pCell); } /** @@ -243,87 +210,33 @@ class LookupRef * Excel Function: * =OFFSET(cellAddress, rows, cols, [height], [width]) * - * @param null|string $cellAddress The reference from which you want to base the offset. Reference must refer to a cell or - * range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value. - * @param mixed $rows The number of rows, up or down, that you want the upper-left cell to refer to. - * Using 5 as the rows argument specifies that the upper-left cell in the reference is - * five rows below reference. Rows can be positive (which means below the starting reference) - * or negative (which means above the starting reference). - * @param mixed $columns The number of columns, to the left or right, that you want the upper-left cell of the result - * to refer to. Using 5 as the cols argument specifies that the upper-left cell in the - * reference is five columns to the right of reference. Cols can be positive (which means - * to the right of the starting reference) or negative (which means to the left of the - * starting reference). - * @param mixed $height The height, in number of rows, that you want the returned reference to be. Height must be a positive number. - * @param mixed $width The width, in number of columns, that you want the returned reference to be. Width must be a positive number. + * @Deprecated 1.18.0 * - * @return string A reference to a cell or range of cells + * @see Use the OFFSET() method in the LookupRef\Offset class instead + * + * @param null|string $cellAddress The reference from which you want to base the offset. + * Reference must refer to a cell or range of adjacent cells; + * otherwise, OFFSET returns the #VALUE! error value. + * @param mixed $rows The number of rows, up or down, that you want the upper-left cell to refer to. + * Using 5 as the rows argument specifies that the upper-left cell in the + * reference is five rows below reference. Rows can be positive (which means + * below the starting reference) or negative (which means above the starting + * reference). + * @param mixed $columns The number of columns, to the left or right, that you want the upper-left cell + * of the result to refer to. Using 5 as the cols argument specifies that the + * upper-left cell in the reference is five columns to the right of reference. + * Cols can be positive (which means to the right of the starting reference) + * or negative (which means to the left of the starting reference). + * @param mixed $height The height, in number of rows, that you want the returned reference to be. + * Height must be a positive number. + * @param mixed $width The width, in number of columns, that you want the returned reference to be. + * Width must be a positive number. + * + * @return array|string An array containing a cell or range of cells, or a string on error */ public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $height = null, $width = null, ?Cell $pCell = null) { - $rows = Functions::flattenSingleValue($rows); - $columns = Functions::flattenSingleValue($columns); - $height = Functions::flattenSingleValue($height); - $width = Functions::flattenSingleValue($width); - if ($cellAddress === null) { - return 0; - } - - if (!is_object($pCell)) { - return Functions::REF(); - } - - $sheetName = null; - if (strpos($cellAddress, '!')) { - [$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); - $sheetName = trim($sheetName, "'"); - } - if (strpos($cellAddress, ':')) { - [$startCell, $endCell] = explode(':', $cellAddress); - } else { - $startCell = $endCell = $cellAddress; - } - [$startCellColumn, $startCellRow] = Coordinate::coordinateFromString($startCell); - [$endCellColumn, $endCellRow] = Coordinate::coordinateFromString($endCell); - - $startCellRow += $rows; - $startCellColumn = Coordinate::columnIndexFromString($startCellColumn) - 1; - $startCellColumn += $columns; - - if (($startCellRow <= 0) || ($startCellColumn < 0)) { - return Functions::REF(); - } - $endCellColumn = Coordinate::columnIndexFromString($endCellColumn) - 1; - if (($width != null) && (!is_object($width))) { - $endCellColumn = $startCellColumn + $width - 1; - } else { - $endCellColumn += $columns; - } - $startCellColumn = Coordinate::stringFromColumnIndex($startCellColumn + 1); - - if (($height != null) && (!is_object($height))) { - $endCellRow = $startCellRow + $height - 1; - } else { - $endCellRow += $rows; - } - - if (($endCellRow <= 0) || ($endCellColumn < 0)) { - return Functions::REF(); - } - $endCellColumn = Coordinate::stringFromColumnIndex($endCellColumn + 1); - - $cellAddress = $startCellColumn . $startCellRow; - if (($startCellColumn != $endCellColumn) || ($startCellRow != $endCellRow)) { - $cellAddress .= ':' . $endCellColumn . $endCellRow; - } - - if ($sheetName !== null) { - $pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName); - } else { - $pSheet = $pCell->getWorksheet(); - } - - return Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false); + return Offset::OFFSET($cellAddress, $rows, $columns, $height, $width, $pCell); } /** @@ -370,6 +283,10 @@ class LookupRef * Excel Function: * =MATCH(lookup_value, lookup_array, [match_type]) * + * @Deprecated 1.18.0 + * + * @see Use the MATCH() method in the LookupRef\ExcelMatch class instead + * * @param mixed $lookupValue The value that you want to match in lookup_array * @param mixed $lookupArray The range of cells being searched * @param mixed $matchType The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php b/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php new file mode 100644 index 00000000..690b32e4 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php @@ -0,0 +1,75 @@ +getParent() : null) + ->extractCellRange($cellAddress, $pSheet, false); + } + + private static function extractWorksheet($cellAddress, Cell $pCell): array + { + $sheetName = ''; + if (strpos($cellAddress, '!') !== false) { + [$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); + $sheetName = trim($sheetName, "'"); + } + + $pSheet = ($sheetName !== '') + ? $pCell->getWorksheet()->getParent()->getSheetByName($sheetName) + : $pCell->getWorksheet(); + + return [$cellAddress, $pSheet]; + } +} diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php new file mode 100644 index 00000000..25ec498b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php @@ -0,0 +1,136 @@ +getParent() : null) + ->extractCellRange($cellAddress, $pSheet, false); + } + + private static function extractWorksheet($cellAddress, Cell $pCell): array + { + $sheetName = ''; + if (strpos($cellAddress, '!') !== false) { + [$sheetName, $cellAddress] = Worksheet::extractSheetTitle($cellAddress, true); + $sheetName = trim($sheetName, "'"); + } + + $pSheet = ($sheetName !== '') + ? $pCell->getWorksheet()->getParent()->getSheetByName($sheetName) + : $pCell->getWorksheet(); + + return [$cellAddress, $pSheet]; + } + + private static function adjustEndCellColumnForWidth(string $endCellColumn, $width, int $startCellColumn, $columns) + { + $endCellColumn = Coordinate::columnIndexFromString($endCellColumn) - 1; + if (($width !== null) && (!is_object($width))) { + $endCellColumn = $startCellColumn + (int) $width - 1; + } else { + $endCellColumn += (int) $columns; + } + + return $endCellColumn; + } + + private static function adustEndCellRowForHeight($height, int $startCellRow, $rows, $endCellRow): int + { + if (($height !== null) && (!is_object($height))) { + $endCellRow = $startCellRow + (int) $height - 1; + } else { + $endCellRow += (int) $rows; + } + + return $endCellRow; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php new file mode 100644 index 00000000..f1018e7f --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php @@ -0,0 +1,55 @@ +getMockBuilder(Calculation::class) +// ->setMethods(['getInstance', 'extractCellRange']) +// ->disableOriginalConstructor() +// ->getMock(); +// $calculation->method('getInstance') +// ->willReturn($calculation); +// $calculation->method('extractCellRange') +// ->willReturn([]); +// +// $worksheet = $this->getMockBuilder(Cell::class) +// ->setMethods(['getParent']) +// ->disableOriginalConstructor() +// ->getMock(); +// +// $cell = $this->getMockBuilder(Cell::class) +// ->setMethods(['getWorksheet']) +// ->disableOriginalConstructor() +// ->getMock(); +// $cell->method('getWorksheet') +// ->willReturn($worksheet); + + $result = LookupRef::INDIRECT($cellReference); + self::assertSame($expectedResult, $result); + } + + public function providerINDIRECT() + { + return require 'tests/data/Calculation/LookupRef/INDIRECT.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php new file mode 100644 index 00000000..631af08d --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php @@ -0,0 +1,32 @@ + Date: Sun, 14 Mar 2021 12:04:07 -0700 Subject: [PATCH 114/187] Coverage for Helper/Samples (#1920) * Coverage for Helper/Samples I was perplexed by the fact that Helper/Samples seemed to be entirely uncovered when running the test suite, since I know all the samples are run as part of the test. I think that what must be happening is that the Helper code is invoked mostly as part of a Data Provider (and therefore not counted), not as part of the test proper (which would count). So, this change adds a small number of tests which result in Samples being 100% covered. Covering one statement was tricky - simulating the inability to create a test directory. Mocking, a technique I have not used before, solves this problem admirably. * Suggestions From Mark Baker Tests changed from assertEquals to assertSame. Added @covers annotation to test class. Validate parameter for method being mocked. --- src/PhpSpreadsheet/Helper/Sample.php | 13 ++++--- .../Helper/SampleCoverageTest.php | 39 +++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Helper/SampleCoverageTest.php diff --git a/src/PhpSpreadsheet/Helper/Sample.php b/src/PhpSpreadsheet/Helper/Sample.php index a91b195e..c84c3930 100644 --- a/src/PhpSpreadsheet/Helper/Sample.php +++ b/src/PhpSpreadsheet/Helper/Sample.php @@ -71,7 +71,7 @@ class Sample /** * Returns an array of all known samples. * - * @return string[] [$name => $path] + * @return string[][] [$name => $path] */ public function getSamples() { @@ -132,6 +132,11 @@ class Sample $this->logEndingNotes(); } + protected function isDirOrMkdir(string $folder): bool + { + return \is_dir($folder) || \mkdir($folder); + } + /** * Returns the temporary directory and make sure it exists. * @@ -140,10 +145,8 @@ class Sample private function getTemporaryFolder() { $tempFolder = sys_get_temp_dir() . '/phpspreadsheet'; - if (!is_dir($tempFolder)) { - if (!mkdir($tempFolder) && !is_dir($tempFolder)) { - throw new RuntimeException(sprintf('Directory "%s" was not created', $tempFolder)); - } + if (!$this->isDirOrMkdir($tempFolder)) { + throw new RuntimeException(sprintf('Directory "%s" was not created', $tempFolder)); } return $tempFolder; diff --git a/tests/PhpSpreadsheetTests/Helper/SampleCoverageTest.php b/tests/PhpSpreadsheetTests/Helper/SampleCoverageTest.php new file mode 100644 index 00000000..f3f616fe --- /dev/null +++ b/tests/PhpSpreadsheetTests/Helper/SampleCoverageTest.php @@ -0,0 +1,39 @@ +getSamples(); + self::assertArrayHasKey('Basic', $samples); + $basic = $samples['Basic']; + self::assertArrayHasKey('02 Types', $basic); + self::assertSame('Basic/02_Types.php', $basic['02 Types']); + self::assertSame('phpunit', $helper->getPageTitle()); + self::assertSame('

phpunit

', $helper->getPageHeading()); + } + + public function testDirectoryFail(): void + { + $this->expectException(RuntimeException::class); + + $helper = $this->getMockBuilder(Sample::class) + ->onlyMethods(['isDirOrMkdir']) + ->getMock(); + $helper->expects(self::once()) + ->method('isDirOrMkdir') + ->with(self::isType('string')) + ->willReturn(false); + self::assertSame('', $helper->getFilename('a.xlsx')); + } +} From d99a4a3fac622298010ceca2796bdc476801ad13 Mon Sep 17 00:00:00 2001 From: oleibman Date: Sun, 14 Mar 2021 12:04:50 -0700 Subject: [PATCH 115/187] Improve Coverage of BIN2DEC etc. (#1902) * Improve Coverage of BIN2DEC etc. The following functions have some special handling depending on the Calculation mode: - BIN2DEC - BIN2HEX - BIN2OCT - DEC2BIN - DEC2HEX - DEC2OCT - HEX2BIN - HEX2DEC - HEX2OCT - OCT2BIN - OCT2DEC - OCT2HEX Ods accepts boolean for its numeric argument. This had already been coded, but there were no tests for it. Gnumeric allows the use of non-integer argument where Excel/Ods do not. The existing code allowed this for certain functions but not for others. Gnumeric consistently allows it, so there is no need for parameter gnumericCheck in convertBase::ValidateValue. Again, there were no tests for this. There were some minor changes needed: - In functions where you are allowed to specify the numnber of "places" in the result, there is an upper bound of 10 which had not been enforced. - Negative values were not handled correctly in some cases. - There was at least one (avoidable) error on a 32-bit system. - Some upper and lower bounds were not being enforced. In addition to enforcing those, the bounds are now defined as class constants in ConvertDecimal. Many tests have been added, so that Engineering is now almost 100% covered. The exception is some BESSEL code. There have been some recent changes to BESSEL which are not yet part of my fork, so I could not address those now. However, I freely admit that, when I looked at the uncovered portion, it seemed like it might be a difficult task, so I probably wouldn't have tackled it anyhow. In particular, the uncovered code seemed to deal with very large numbers, and, although PhpSpreadsheet and Excel both give very large results for these conditions, their answers are not particularly close to each other. I think we're dealing with resuts approaching infinity. More study is needed. --- .../Calculation/Engineering/ConvertBase.php | 10 +- .../Calculation/Engineering/ConvertBinary.php | 18 +-- .../Engineering/ConvertDecimal.php | 51 ++++++-- .../Calculation/Engineering/ConvertHex.php | 7 +- .../Calculation/Engineering/ConvertOctal.php | 6 +- .../Functions/Engineering/Bin2DecTest.php | 67 +++++++++- .../Functions/Engineering/Bin2HexTest.php | 67 +++++++++- .../Functions/Engineering/Bin2OctTest.php | 67 +++++++++- .../Functions/Engineering/Dec2BinTest.php | 67 +++++++++- .../Functions/Engineering/Dec2HexTest.php | 73 ++++++++++- .../Functions/Engineering/Dec2OctTest.php | 67 +++++++++- .../Functions/Engineering/Hex2BinTest.php | 70 ++++++++++- .../Functions/Engineering/Hex2DecTest.php | 70 ++++++++++- .../Functions/Engineering/Hex2OctTest.php | 67 +++++++++- .../Engineering/MovedFunctionsTest.php | 31 +++++ .../Functions/Engineering/Oct2BinTest.php | 67 +++++++++- .../Functions/Engineering/Oct2DecTest.php | 67 +++++++++- .../Functions/Engineering/Oct2HexTest.php | 67 +++++++++- .../data/Calculation/Engineering/BIN2DEC.php | 67 ++++------ .../data/Calculation/Engineering/BIN2HEX.php | 101 +++++---------- .../data/Calculation/Engineering/BIN2OCT.php | 106 +++++----------- .../data/Calculation/Engineering/DEC2BIN.php | 119 +++++------------- .../data/Calculation/Engineering/DEC2HEX.php | 104 +++++---------- .../data/Calculation/Engineering/DEC2OCT.php | 76 ++++------- .../data/Calculation/Engineering/HEX2BIN.php | 96 +++++--------- .../data/Calculation/Engineering/HEX2DEC.php | 86 ++++--------- .../data/Calculation/Engineering/HEX2OCT.php | 80 ++++-------- .../data/Calculation/Engineering/OCT2BIN.php | 84 ++++--------- .../data/Calculation/Engineering/OCT2DEC.php | 53 +++----- .../data/Calculation/Engineering/OCT2HEX.php | 60 ++++----- 30 files changed, 1179 insertions(+), 792 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedFunctionsTest.php diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php index 5122e011..a095690d 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class ConvertBase { - protected static function validateValue($value, bool $gnumericCheck = false): string + protected static function validateValue($value): string { if (is_bool($value)) { if (Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_OPENOFFICE) { @@ -16,8 +16,10 @@ class ConvertBase $value = (int) $value; } - if ($gnumericCheck && Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - $value = floor((float) $value); + if (is_numeric($value)) { + if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { + $value = floor((float) $value); + } } return strtoupper((string) $value); @@ -30,7 +32,7 @@ class ConvertBase } if (is_numeric($places)) { - if ($places < 0) { + if ($places < 0 || $places > 10) { throw new Exception(Functions::NAN()); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php index 57f9fc41..ff4873ac 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php @@ -25,7 +25,7 @@ class ConvertBinary extends ConvertBase public static function toDecimal($value): string { try { - $value = self::validateValue(Functions::flattenSingleValue($value), true); + $value = self::validateValue(Functions::flattenSingleValue($value)); $value = self::validateBinary($value); } catch (Exception $e) { return $e->getMessage(); @@ -65,7 +65,7 @@ class ConvertBinary extends ConvertBase public static function toHex($value, $places = null): string { try { - $value = self::validateValue(Functions::flattenSingleValue($value), true); + $value = self::validateValue(Functions::flattenSingleValue($value)); $value = self::validateBinary($value); $places = self::validatePlaces(Functions::flattenSingleValue($places)); } catch (Exception $e) { @@ -73,8 +73,11 @@ class ConvertBinary extends ConvertBase } if (strlen($value) == 10) { - // Two's Complement - return str_repeat('F', 8) . substr(strtoupper(dechex((int) bindec(substr($value, -9)))), -2); + $high2 = substr($value, 0, 2); + $low8 = substr($value, 2); + $xarr = ['00' => '00000000', '01' => '00000001', '10' => 'FFFFFFFE', '11' => 'FFFFFFFF']; + + return $xarr[$high2] . strtoupper(substr('0' . dechex((int) bindec($low8)), -2)); } $hexVal = (string) strtoupper(dechex((int) bindec($value))); @@ -105,16 +108,15 @@ class ConvertBinary extends ConvertBase public static function toOctal($value, $places = null): string { try { - $value = self::validateValue(Functions::flattenSingleValue($value), true); + $value = self::validateValue(Functions::flattenSingleValue($value)); $value = self::validateBinary($value); $places = self::validatePlaces(Functions::flattenSingleValue($places)); } catch (Exception $e) { return $e->getMessage(); } - if (strlen($value) == 10) { - // Two's Complement - return str_repeat('7', 7) . substr(strtoupper(decoct((int) bindec(substr($value, -9)))), -3); + if (strlen($value) == 10 && substr($value, 0, 1) === '1') { // Two's Complement + return str_repeat('7', 6) . strtoupper(decoct((int) bindec("11$value"))); } $octVal = (string) decoct((int) bindec($value)); diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php index bd249633..a34332fb 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertDecimal.php @@ -7,6 +7,13 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class ConvertDecimal extends ConvertBase { + const LARGEST_OCTAL_IN_DECIMAL = 536870911; + const SMALLEST_OCTAL_IN_DECIMAL = -536870912; + const LARGEST_BINARY_IN_DECIMAL = 511; + const SMALLEST_BINARY_IN_DECIMAL = -512; + const LARGEST_HEX_IN_DECIMAL = 549755813887; + const SMALLEST_HEX_IN_DECIMAL = -549755813888; + /** * toBinary. * @@ -43,16 +50,13 @@ class ConvertDecimal extends ConvertBase } $value = (int) floor((float) $value); - if ($value < -512 || $value > 511) { + if ($value > self::LARGEST_BINARY_IN_DECIMAL || $value < self::SMALLEST_BINARY_IN_DECIMAL) { return Functions::NAN(); } $r = decbin($value); // Two's Complement $r = substr($r, -10); - if (strlen($r) >= 11) { - return Functions::NAN(); - } return self::nbrConversionFormat($r, $places); } @@ -92,16 +96,37 @@ class ConvertDecimal extends ConvertBase return $e->getMessage(); } - $value = (int) floor((float) $value); - $r = strtoupper(dechex($value)); - if (strlen($r) == 8) { - // Two's Complement - $r = 'FF' . $r; + $value = floor((float) $value); + if ($value > self::LARGEST_HEX_IN_DECIMAL || $value < self::SMALLEST_HEX_IN_DECIMAL) { + return Functions::NAN(); } + $r = strtoupper(dechex((int) $value)); + $r = self::hex32bit($value, $r); return self::nbrConversionFormat($r, $places); } + public static function hex32bit(float $value, string $hexstr, bool $force = false): string + { + if (PHP_INT_SIZE === 4 || $force) { + if ($value >= 2 ** 32) { + $quotient = (int) ($value / (2 ** 32)); + + return strtoupper(substr('0' . dechex($quotient), -2) . $hexstr); + } + if ($value < -(2 ** 32)) { + $quotient = 256 - (int) ceil((-$value) / (2 ** 32)); + + return strtoupper(substr('0' . dechex($quotient), -2) . substr("00000000$hexstr", -8)); + } + if ($value < 0) { + return "FF$hexstr"; + } + } + + return $hexstr; + } + /** * toOctal. * @@ -138,11 +163,11 @@ class ConvertDecimal extends ConvertBase } $value = (int) floor((float) $value); - $r = decoct($value); - if (strlen($r) == 11) { - // Two's Complement - $r = substr($r, -10); + if ($value > self::LARGEST_OCTAL_IN_DECIMAL || $value < self::SMALLEST_OCTAL_IN_DECIMAL) { + return Functions::NAN(); } + $r = decoct($value); + $r = substr($r, -10); return self::nbrConversionFormat($r, $places); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php index 9147bf08..cbf155ed 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php @@ -42,7 +42,9 @@ class ConvertHex extends ConvertBase return $e->getMessage(); } - return ConvertDecimal::toBinary(self::toDecimal($value), $places); + $dec = self::toDecimal($value); + + return ConvertDecimal::toBinary($dec, $places); } /** @@ -129,9 +131,6 @@ class ConvertHex extends ConvertBase } $decimal = self::toDecimal($value); - if ($decimal < -536870912 || $decimal > 536870911) { - return Functions::NAN(); - } return ConvertDecimal::toOctal($decimal, $places); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php index 1e8823ad..872f0b70 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php @@ -127,14 +127,16 @@ class ConvertOctal extends ConvertBase return $e->getMessage(); } - $hexVal = strtoupper(dechex((int) self::toDecimal((int) $value))); + $hexVal = strtoupper(dechex((int) self::toDecimal($value))); + $hexVal = (PHP_INT_SIZE === 4 && strlen($value) === 10 && $value[0] >= '4') ? "FF$hexVal" : $hexVal; return self::nbrConversionFormat($hexVal, $places); } protected static function validateOctal(string $value): string { - if (strlen($value) > preg_match_all('/[01234567]/', $value)) { + $numDigits = (int) preg_match_all('/[01234567]/', $value); + if (strlen($value) > $numDigits || $numDigits > 10) { throw new Exception(Functions::NAN()); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php index faba3de8..bcefa891 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Bin2DecTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerBIN2DEC * * @param mixed $expectedResult + * @param mixed $formula */ - public function testBIN2DEC($expectedResult, ...$args): void + public function testBin2Dec($expectedResult, $formula): void { - $result = Engineering::BINTODEC(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=BIN2DEC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Bin2DecTest extends TestCase { return require 'tests/data/Calculation/Engineering/BIN2DEC.php'; } + + /** + * @dataProvider providerBIN2DEC + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testBIN2DECOds($expectedResult, $formula): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=BIN2DEC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testBIN2DECFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=BIN2DEC(101.1)'); + self::assertEquals(5, $sheet->getCell($cell)->getCalculatedValue(), 'Gnumeric'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=BIN2DEC(101.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue(), 'Ods'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=BIN2DEC(101.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue(), 'Excel'); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php index 2a16d5ac..2cbea34a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Bin2HexTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerBIN2HEX * * @param mixed $expectedResult + * @param mixed $formula */ - public function testBIN2HEX($expectedResult, ...$args): void + public function testBin2Hex($expectedResult, $formula): void { - $result = Engineering::BINTOHEX(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=BIN2HEX($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Bin2HexTest extends TestCase { return require 'tests/data/Calculation/Engineering/BIN2HEX.php'; } + + /** + * @dataProvider providerBIN2HEX + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testBIN2HEXOds($expectedResult, $formula): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=BIN2HEX($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testBIN2HEXFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=BIN2HEX(101.1)'); + self::assertEquals(5, $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=BIN2HEX(101.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=BIN2HEX(101.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php index 78db6a6e..e76778f2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Bin2OctTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerBIN2OCT * * @param mixed $expectedResult + * @param mixed $formula */ - public function testBIN2OCT($expectedResult, ...$args): void + public function testBin2Oct($expectedResult, $formula): void { - $result = Engineering::BINTOOCT(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=BIN2OCT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Bin2OctTest extends TestCase { return require 'tests/data/Calculation/Engineering/BIN2OCT.php'; } + + /** + * @dataProvider providerBIN2OCT + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testBIN2OCTOds($expectedResult, $formula): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=BIN2OCT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testBIN2OCTFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=BIN2OCT(101.1)'); + self::assertEquals(5, $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=BIN2OCT(101.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=BIN2OCT(101.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php index 3626ac6b..420af2c5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Dec2BinTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerDEC2BIN * * @param mixed $expectedResult + * @param mixed $formula */ - public function testDEC2BIN($expectedResult, ...$args): void + public function testDEC2BIN($expectedResult, $formula): void { - $result = Engineering::DECTOBIN(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 5); + $sheet->getCell('A1')->setValue("=DEC2BIN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Dec2BinTest extends TestCase { return require 'tests/data/Calculation/Engineering/DEC2BIN.php'; } + + /** + * @dataProvider providerDEC2BIN + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testDEC2BINOds($expectedResult, $formula): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 5); + $sheet->getCell('A1')->setValue("=DEC2BIN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testDEC2BINFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=DEC2BIN(5.1)'); + self::assertEquals(101, $sheet->getCell($cell)->getCalculatedValue(), 'Gnumeric'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=DEC2BIN(5.1)'); + self::assertEquals(101, $sheet->getCell($cell)->getCalculatedValue(), 'Ods'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=DEC2BIN(5.1)'); + self::assertEquals(101, $sheet->getCell($cell)->getCalculatedValue(), 'Excel'); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php index d191f620..fcd9c52a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php @@ -3,24 +3,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Dec2HexTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerDEC2HEX * * @param mixed $expectedResult + * @param mixed $formula */ - public function testDEC2HEX($expectedResult, ...$args): void + public function testDEC2HEX($expectedResult, $formula): void { - $result = Engineering::DECTOHEX(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 17); + $sheet->getCell('A1')->setValue("=DEC2HEX($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +45,54 @@ class Dec2HexTest extends TestCase { return require 'tests/data/Calculation/Engineering/DEC2HEX.php'; } + + /** + * @dataProvider providerDEC2HEX + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testDEC2HEXOds($expectedResult, $formula): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 17); + $sheet->getCell('A1')->setValue("=DEC2HEX($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testDEC2HEXFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=DEC2HEX(17.1)'); + self::assertEquals(11, $sheet->getCell($cell)->getCalculatedValue(), 'Gnumeric'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=DEC2HEX(17.1)'); + self::assertEquals(11, $sheet->getCell($cell)->getCalculatedValue(), 'Ods'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=DEC2HEX(17.1)'); + self::assertEquals(11, $sheet->getCell($cell)->getCalculatedValue(), 'Excel'); + } + + public function test32bitHex(): void + { + self::assertEquals('A2DE246000', Engineering\ConvertDecimal::hex32bit(-400000000000, 'DE246000', true)); + self::assertEquals('7FFFFFFFFF', Engineering\ConvertDecimal::hex32bit(549755813887, 'FFFFFFFF', true)); + self::assertEquals('FFFFFFFFFF', Engineering\ConvertDecimal::hex32bit(-1, 'FFFFFFFF', true)); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php index 61eb3dbb..19846a3b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Dec2OctTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerDEC2OCT * * @param mixed $expectedResult + * @param mixed $formula */ - public function testDEC2OCT($expectedResult, ...$args): void + public function testDEC2OCT($expectedResult, $formula): void { - $result = Engineering::DECTOOCT(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 17); + $sheet->getCell('A1')->setValue("=DEC2OCT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Dec2OctTest extends TestCase { return require 'tests/data/Calculation/Engineering/DEC2OCT.php'; } + + /** + * @dataProvider providerDEC2OCT + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testDEC2OCTOds($expectedResult, $formula): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 17); + $sheet->getCell('A1')->setValue("=DEC2OCT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testDEC2OCTFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=DEC2OCT(17.1)'); + self::assertEquals(21, $sheet->getCell($cell)->getCalculatedValue(), 'Gnumeric'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=DEC2OCT(17.1)'); + self::assertEquals(21, $sheet->getCell($cell)->getCalculatedValue(), 'Ods'); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=DEC2OCT(17.1)'); + self::assertEquals(21, $sheet->getCell($cell)->getCalculatedValue(), 'Excel'); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php index 44d8908d..45973004 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Hex2BinTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerHEX2BIN * * @param mixed $expectedResult + * @param mixed $formula */ - public function testHEX2BIN($expectedResult, ...$args): void + public function testHEX2BIN($expectedResult, $formula): void { - $result = Engineering::HEXTOBIN(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 'B'); + $sheet->getCell('A1')->setValue("=HEX2BIN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,50 @@ class Hex2BinTest extends TestCase { return require 'tests/data/Calculation/Engineering/HEX2BIN.php'; } + + /** + * @dataProvider providerHEX2BIN + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testHEX2BINOds($expectedResult, $formula): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 'B'); + $sheet->getCell('A1')->setValue("=HEX2BIN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testHEX2BINFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=HEX2BIN(10.1)'); + self::assertEquals('10000', $sheet->getCell($cell)->getCalculatedValue()); + $cell = 'F21'; + $sheet->setCellValue($cell, '=HEX2BIN("A.1")'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=HEX2BIN(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=HEX2BIN(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php index b388b2b7..264ec3e3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Hex2DecTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerHEX2DEC * * @param mixed $expectedResult + * @param mixed $formula */ - public function testHEX2DEC($expectedResult, ...$args): void + public function testHEX2DEC($expectedResult, $formula): void { - $result = Engineering::HEXTODEC(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 'B'); + $sheet->getCell('A1')->setValue("=HEX2DEC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,50 @@ class Hex2DecTest extends TestCase { return require 'tests/data/Calculation/Engineering/HEX2DEC.php'; } + + /** + * @dataProvider providerHEX2DEC + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testHEX2DECOds($expectedResult, $formula): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 'B'); + $sheet->getCell('A1')->setValue("=HEX2DEC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testHEX2DECFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=HEX2DEC(10.1)'); + self::assertEquals(16, $sheet->getCell($cell)->getCalculatedValue()); + $cell = 'F21'; + $sheet->setCellValue($cell, '=HEX2DEC("A.1")'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=HEX2DEC(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=HEX2DEC(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue(), 'Excel'); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php index bc0a5cb7..15220178 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Hex2OctTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerHEX2OCT * * @param mixed $expectedResult + * @param mixed $formula */ - public function testHEX2OCT($expectedResult, ...$args): void + public function testHEX2OCT($expectedResult, $formula): void { - $result = Engineering::HEXTOOCT(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 'B'); + $sheet->getCell('A1')->setValue("=HEX2OCT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Hex2OctTest extends TestCase { return require 'tests/data/Calculation/Engineering/HEX2OCT.php'; } + + /** + * @dataProvider providerHEX2OCT + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testHEX2OCTOds($expectedResult, $formula): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 'B'); + $sheet->getCell('A1')->setValue("=HEX2OCT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testHEX2OCTFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=HEX2OCT(10.1)'); + self::assertEquals(20, $sheet->getCell($cell)->getCalculatedValue()); + $cell = 'F21'; + $sheet->setCellValue($cell, '=HEX2OCT("A.1")'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=HEX2OCT(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=HEX2OCT(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue(), 'Excel'); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedFunctionsTest.php new file mode 100644 index 00000000..04ebb131 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedFunctionsTest.php @@ -0,0 +1,31 @@ +compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerOCT2BIN * * @param mixed $expectedResult + * @param mixed $formula */ - public function testOCT2BIN($expectedResult, ...$args): void + public function testOCT2BIN($expectedResult, $formula): void { - $result = Engineering::OCTTOBIN(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=OCT2BIN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Oct2BinTest extends TestCase { return require 'tests/data/Calculation/Engineering/OCT2BIN.php'; } + + /** + * @dataProvider providerOCT2BIN + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testOCT2BINOds($expectedResult, $formula): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=OCT2BIN($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testOCT2BINFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=HEX2BIN(10.1)'); + self::assertEquals('10000', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=OCT2BIN(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=OCT2BIN(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php index 87e213ef..b0537289 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Oct2DecTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerOCT2DEC * * @param mixed $expectedResult + * @param mixed $formula */ - public function testOCT2DEC($expectedResult, ...$args): void + public function testOCT2DEC($expectedResult, $formula): void { - $result = Engineering::OCTTODEC(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=OCT2DEC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Oct2DecTest extends TestCase { return require 'tests/data/Calculation/Engineering/OCT2DEC.php'; } + + /** + * @dataProvider providerOCT2DEC + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testOCT2DECOds($expectedResult, $formula): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=OCT2DEC($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testOCT2DECFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=OCT2DEC(10.1)'); + self::assertEquals(8, $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=OCT2DEC(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=OCT2DEC(10.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php index e2d75a78..05703cc9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php @@ -2,25 +2,41 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class Oct2HexTest extends TestCase { + private $compatibilityMode; + protected function setUp(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->compatibilityMode = Functions::getCompatibilityMode(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); } /** * @dataProvider providerOCT2HEX * * @param mixed $expectedResult + * @param mixed $formula */ - public function testOCT2HEX($expectedResult, ...$args): void + public function testOCT2HEX($expectedResult, $formula): void { - $result = Engineering::OCTTOHEX(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=OCT2HEX($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } @@ -28,4 +44,47 @@ class Oct2HexTest extends TestCase { return require 'tests/data/Calculation/Engineering/OCT2HEX.php'; } + + /** + * @dataProvider providerOCT2HEX + * + * @param mixed $expectedResult + * @param mixed $formula + */ + public function testOCT2HEXOds($expectedResult, $formula): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + if ($formula === 'true') { + $expectedResult = 1; + } elseif ($formula === 'false') { + $expectedResult = 0; + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 101); + $sheet->getCell('A1')->setValue("=OCT2HEX($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function testOCT2HEXFrac(): void + { + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + $cell = 'G1'; + $sheet->setCellValue($cell, '=OCT2HEX(20.1)'); + self::assertEquals(10, $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + $cell = 'O1'; + $sheet->setCellValue($cell, '=OCT2HEX(20.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $cell = 'E1'; + $sheet->setCellValue($cell, '=OCT2HEX(20.1)'); + self::assertEquals('#NUM!', $sheet->getCell($cell)->getCalculatedValue()); + } } diff --git a/tests/data/Calculation/Engineering/BIN2DEC.php b/tests/data/Calculation/Engineering/BIN2DEC.php index ce9b6d34..4722d8e7 100644 --- a/tests/data/Calculation/Engineering/BIN2DEC.php +++ b/tests/data/Calculation/Engineering/BIN2DEC.php @@ -1,49 +1,26 @@ Date: Sun, 14 Mar 2021 12:05:31 -0700 Subject: [PATCH 116/187] Bitwise Functions and 32-bit (#1900) * Bitwise Functions and 32-bit When running the test suite with 32-bit PHP, a failure was reported in BITLSHIFT. In fact, all of the following are vulnerable to problems, and didn't report any failures only because of a scarcity of tests: - BITAND - BITOR - BITXOR - BITRSHIFT - BITLSHIFT Those last 2 can be resolved fairly easily by using multiplication by a power of 2 rather than shifting. The first 3 are a tougher nut to crack, and I will continue to think how they might best be approached. For now, I have added skippable tests for each of them, which at least documents the problem. Aside from adding many new tests, some bugs were correctd: - The function list in Calculation.php pointed BITXOR to BITOR. - All 5 functions allow null/false/true parameters. - BIT*SHIFT shift amount must be numeric, can be negative, allows decimal portion (which is truncated to integer), and has an absolute value limit of 53. - Because BITRSHIFT allows negative shift amount, its result can overflow (in which case return NAN). - All 5 functions disallow negative parameters (except ...SHIFT second parameter). This was coded, but the code had been thwarted by an earlier is_int test. * Full Support for AND/OR/XOR on 32-bit Previous version did not support operands 2**32 through 2**48. --- .../Calculation/Calculation.php | 2 +- .../Calculation/Engineering/BitWise.php | 103 ++++++++++++++---- .../Functions/Engineering/BitAndTest.php | 21 ++-- .../Functions/Engineering/BitLShiftTest.php | 21 ++-- .../Functions/Engineering/BitOrTest.php | 21 ++-- .../Functions/Engineering/BitRShiftTest.php | 21 ++-- .../Functions/Engineering/BitXorTest.php | 21 ++-- .../Engineering/MovedBitwiseTest.php | 24 ++++ tests/data/Calculation/Engineering/BITAND.php | 45 +++++--- .../Calculation/Engineering/BITLSHIFT.php | 46 +++++--- tests/data/Calculation/Engineering/BITOR.php | 50 +++++---- .../Calculation/Engineering/BITRSHIFT.php | 43 ++++++-- tests/data/Calculation/Engineering/BITXOR.php | 48 ++++---- 13 files changed, 308 insertions(+), 158 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedBitwiseTest.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index c88eff31..fcfebba6 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -448,7 +448,7 @@ class Calculation ], 'BITXOR' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering\BitWise::class, 'BITOR'], + 'functionCall' => [Engineering\BitWise::class, 'BITXOR'], 'argumentCount' => '2', ], 'BITLSHIFT' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php b/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php index 494b5685..9958f054 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BitWise.php @@ -7,6 +7,18 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BitWise { + const SPLIT_DIVISOR = 2 ** 24; + + /** + * Split a number into upper and lower portions for full 32-bit support. + * + * @param float|int $number + */ + private static function splitNumber($number): array + { + return [floor($number / self::SPLIT_DIVISOR), fmod($number, self::SPLIT_DIVISOR)]; + } + /** * BITAND. * @@ -28,8 +40,10 @@ class BitWise } catch (Exception $e) { return $e->getMessage(); } + $split1 = self::splitNumber($number1); + $split2 = self::splitNumber($number2); - return $number1 & $number2; + return self::SPLIT_DIVISOR * ($split1[0] & $split2[0]) + ($split1[1] & $split2[1]); } /** @@ -54,7 +68,10 @@ class BitWise return $e->getMessage(); } - return $number1 | $number2; + $split1 = self::splitNumber($number1); + $split2 = self::splitNumber($number2); + + return self::SPLIT_DIVISOR * ($split1[0] | $split2[0]) + ($split1[1] | $split2[1]); } /** @@ -79,7 +96,10 @@ class BitWise return $e->getMessage(); } - return $number1 ^ $number2; + $split1 = self::splitNumber($number1); + $split2 = self::splitNumber($number2); + + return self::SPLIT_DIVISOR * ($split1[0] ^ $split2[0]) + ($split1[1] ^ $split2[1]); } /** @@ -93,19 +113,18 @@ class BitWise * @param int $number * @param int $shiftAmount * - * @return int|string + * @return float|int|string */ public static function BITLSHIFT($number, $shiftAmount) { try { $number = self::validateBitwiseArgument($number); + $shiftAmount = self::validateShiftAmount($shiftAmount); } catch (Exception $e) { return $e->getMessage(); } - $shiftAmount = Functions::flattenSingleValue($shiftAmount); - - $result = $number << $shiftAmount; + $result = floor($number * (2 ** $shiftAmount)); if ($result > 2 ** 48 - 1) { return Functions::NAN(); } @@ -124,19 +143,49 @@ class BitWise * @param int $number * @param int $shiftAmount * - * @return int|string + * @return float|int|string */ public static function BITRSHIFT($number, $shiftAmount) { try { $number = self::validateBitwiseArgument($number); + $shiftAmount = self::validateShiftAmount($shiftAmount); } catch (Exception $e) { return $e->getMessage(); } - $shiftAmount = Functions::flattenSingleValue($shiftAmount); + $result = floor($number / (2 ** $shiftAmount)); + if ($result > 2 ** 48 - 1) { // possible because shiftAmount can be negative + return Functions::NAN(); + } - return $number >> $shiftAmount; + return $result; + } + + /** + * Validate arguments passed to the bitwise functions. + * + * @param mixed $value + * + * @return float|int + */ + private static function validateBitwiseArgument($value) + { + self::nullFalseTrueToNumber($value); + + if (is_numeric($value)) { + if ($value == floor($value)) { + if (($value > 2 ** 48 - 1) || ($value < 0)) { + throw new Exception(Functions::NAN()); + } + + return floor($value); + } + + throw new Exception(Functions::NAN()); + } + + throw new Exception(Functions::VALUE()); } /** @@ -146,25 +195,33 @@ class BitWise * * @return int */ - private static function validateBitwiseArgument($value) + private static function validateShiftAmount($value) { - $value = Functions::flattenSingleValue($value); + self::nullFalseTrueToNumber($value); - if (is_int($value)) { - return $value; - } elseif (is_numeric($value)) { - if ($value == (int) ($value)) { - $value = (int) ($value); - if (($value > 2 ** 48 - 1) || ($value < 0)) { - throw new Exception(Functions::NAN()); - } - - return $value; + if (is_numeric($value)) { + if (abs($value) > 53) { + throw new Exception(Functions::NAN()); } - throw new Exception(Functions::NAN()); + return (int) $value; } throw new Exception(Functions::VALUE()); } + + /** + * Many functions accept null/false/true argument treated as 0/0/1. + * + * @param mixed $number + */ + public static function nullFalseTrueToNumber(&$number): void + { + $number = Functions::flattenSingleValue($number); + if ($number === null) { + $number = 0; + } elseif (is_bool($number)) { + $number = (int) $number; + } + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php index e73efccc..01d006c4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php @@ -2,26 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class BitAndTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerBITAND * * @param mixed $expectedResult - * @param mixed[] $args */ - public function testBITAND($expectedResult, array $args): void + public function testBITAND($expectedResult, string $formula): void { - $result = Engineering::BITAND(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 24); + $sheet->getCell('A1')->setValue("=BITAND($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php index 61aa89b4..f1a716ef 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php @@ -2,26 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class BitLShiftTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerBITLSHIFT * * @param mixed $expectedResult - * @param mixed[] $args */ - public function testBITLSHIFT($expectedResult, array $args): void + public function testBITLSHIFT($expectedResult, string $formula): void { - $result = Engineering::BITLSHIFT(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 8); + $sheet->getCell('A1')->setValue("=BITLSHIFT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php index 857c7466..fce287d9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php @@ -2,26 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class BitOrTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerBITOR * * @param mixed $expectedResult - * @param mixed[] $args */ - public function testBITOR($expectedResult, array $args): void + public function testBITOR($expectedResult, string $formula): void { - $result = Engineering::BITOR(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 8); + $sheet->getCell('A1')->setValue("=BITOR($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php index 26b13d07..40b929e3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php @@ -2,26 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class BitRShiftTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerBITRSHIFT * * @param mixed $expectedResult - * @param mixed[] $args */ - public function testBITRSHIFT($expectedResult, array $args): void + public function testBITRSHIFT($expectedResult, string $formula): void { - $result = Engineering::BITRSHIFT(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 8); + $sheet->getCell('A1')->setValue("=BITRSHIFT($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php index 4415f6da..847e44a2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php @@ -2,26 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Engineering; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class BitXorTest extends TestCase { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerBITXOR * * @param mixed $expectedResult - * @param mixed[] $args */ - public function testBITXOR($expectedResult, array $args): void + public function testBITXOR($expectedResult, string $formula): void { - $result = Engineering::BITXOR(...$args); + if ($expectedResult === 'exception') { + $this->expectException(CalcExp::class); + } + $spreadsheet = new Spreadsheet(); + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setCellValue('A2', 8); + $sheet->getCell('A1')->setValue("=BITXOR($formula)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedBitwiseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedBitwiseTest.php new file mode 100644 index 00000000..457db0d3 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/MovedBitwiseTest.php @@ -0,0 +1,24 @@ += 2**48 + ['#NUM!', '1, power(2, 50)'], // argument >= 2**48 + ['#NUM!', '-2, 1'], // negative argument + ['#NUM!', '2, -1'], // negative argument + ['#NUM!', '-2, -1'], // negative argument + ['#NUM!', '3.1, 1'], // non-integer argument + ['#NUM!', '3, 1.1'], // non-integer argument + [0, '4, Q15'], + [0, '4, null'], + [0, '4, false'], + [1, '3, true'], + ['exception', ''], + ['exception', '2'], + [0, ', 4'], + [0, 'Q15, 4'], + [0, 'false, 4'], + [1, 'true, 5'], + [8, 'A2, 9'], ]; diff --git a/tests/data/Calculation/Engineering/BITLSHIFT.php b/tests/data/Calculation/Engineering/BITLSHIFT.php index ceaf9a33..fee922e4 100644 --- a/tests/data/Calculation/Engineering/BITLSHIFT.php +++ b/tests/data/Calculation/Engineering/BITLSHIFT.php @@ -1,20 +1,34 @@ 2**32 + [16000000000, '8000000000, 1'], // argument > 2**32 + ['#NUM!', 'power(2,50), 1'], // argument >= 2**48 + ['1', 'power(2, 47), -47'], ]; diff --git a/tests/data/Calculation/Engineering/BITOR.php b/tests/data/Calculation/Engineering/BITOR.php index 01640c9f..a98ce380 100644 --- a/tests/data/Calculation/Engineering/BITOR.php +++ b/tests/data/Calculation/Engineering/BITOR.php @@ -1,24 +1,34 @@ = 2**48 + ['#NUM!', '1, power(2, 50)'], // argument >= 2**48 + ['#NUM!', '-2, 1'], // negative argument + ['#NUM!', '2, -1'], // negative argument + ['#NUM!', '-2, -1'], // negative argument + ['#NUM!', '3.1, 1'], // non-integer argument + ['#NUM!', '3, 1.1'], // non-integer argument + [4, '4, Q15'], + [4, '4, null'], + [4, '4, false'], + [5, '4, true'], + ['exception', ''], + ['exception', '2'], + [4, ', 4'], + [4, 'Q15, 4'], + [4, 'false, 4'], + [5, 'true, 4'], + [9, 'A2, 1'], ]; diff --git a/tests/data/Calculation/Engineering/BITRSHIFT.php b/tests/data/Calculation/Engineering/BITRSHIFT.php index 78cacf37..343ccb5c 100644 --- a/tests/data/Calculation/Engineering/BITRSHIFT.php +++ b/tests/data/Calculation/Engineering/BITRSHIFT.php @@ -1,16 +1,35 @@ 2**32 + [8000000000, '16000000000, 1'], // argument > 2**32 + ['#NUM!', 'power(2,50), 1'], // argument >= 2**48 + ['1', 'power(2, 47), 47'], ]; diff --git a/tests/data/Calculation/Engineering/BITXOR.php b/tests/data/Calculation/Engineering/BITXOR.php index 40972c1c..836f327a 100644 --- a/tests/data/Calculation/Engineering/BITXOR.php +++ b/tests/data/Calculation/Engineering/BITXOR.php @@ -1,24 +1,32 @@ = 2**48 + ['#NUM!', '1, power(2, 50)'], // argument >= 2**48 + ['#NUM!', '-2, 1'], // negative argument + ['#NUM!', '2, -1'], // negative argument + ['#NUM!', '-2, -1'], // negative argument + ['#NUM!', '3.1, 1'], // non-integer argument + ['#NUM!', '3, 1.1'], // non-integer argument + [4, '4, Q15'], + [4, '4, null'], + [4, '4, false'], + [5, '4, true'], + ['exception', ''], + ['exception', '2'], + [4, ', 4'], + [4, 'Q15, 4'], + [4, 'false, 4'], + [5, 'true, 4'], + [9, 'A2, 1'], ]; From c920a776499bc20c5d30398320bf879f47e6d43d Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 14 Mar 2021 23:53:13 +0100 Subject: [PATCH 117/187] Some minor refactoring (#1923) * Some minor refactoring --- .../Calculation/Calculation.php | 99 +++++++++++-------- .../Calculation/Logical/Conditional.php | 14 +-- src/PhpSpreadsheet/Cell/Coordinate.php | 4 +- src/PhpSpreadsheet/Document/Properties.php | 30 ------ 4 files changed, 67 insertions(+), 80 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index fcfebba6..5674cb72 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -3345,18 +3345,15 @@ class Calculation } /** - * @param string $cellReference * @param mixed $cellValue - * - * @return bool */ - public function getValueFromCache($cellReference, &$cellValue) + public function getValueFromCache(string $cellReference, &$cellValue): bool { + $this->debugLog->writeDebugLog("Testing cache value for cell {$cellReference}"); // Is calculation cacheing enabled? - // Is the value present in calculation cache? - $this->debugLog->writeDebugLog('Testing cache value for cell ', $cellReference); + // If so, is the required value present in calculation cache? if (($this->calculationCacheEnabled) && (isset($this->calculationCache[$cellReference]))) { - $this->debugLog->writeDebugLog('Retrieving value for cell ', $cellReference, ' from cache'); + $this->debugLog->writeDebugLog("Retrieving value for cell {$cellReference} from cache"); // Return the cached result $cellValue = $this->calculationCache[$cellReference]; @@ -3418,7 +3415,7 @@ class Calculation if (($cellID !== null) && ($this->getValueFromCache($wsCellReference, $cellValue))) { return $cellValue; } - $this->debugLog->writeDebugLog('Evaluating formula for cell ', $wsCellReference); + $this->debugLog->writeDebugLog("Evaluating formula for cell {$wsCellReference}"); if (($wsTitle[0] !== "\x00") && ($this->cyclicReferenceStack->onStack($wsCellReference))) { if ($this->cyclicFormulaCount <= 0) { @@ -3440,7 +3437,7 @@ class Calculation } } - $this->debugLog->writeDebugLog('Formula for cell ', $wsCellReference, ' is ', $formula); + $this->debugLog->writeDebugLog("Formula for cell {$wsCellReference} is {$formula}"); // Parse the formula onto the token stack and calculate the value $this->cyclicReferenceStack->push($wsCellReference); @@ -4805,6 +4802,53 @@ class Calculation return true; } + /** + * @param null|string $cellID + * @param mixed $operand1 + * @param mixed $operand2 + * @param string $operation + * + * @return array + */ + private function executeArrayComparison($cellID, $operand1, $operand2, $operation, Stack &$stack, bool $recursingArrays) + { + $result = []; + if (!is_array($operand2)) { + // Operand 1 is an array, Operand 2 is a scalar + foreach ($operand1 as $x => $operandData) { + $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2)); + $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack); + $r = $stack->pop(); + $result[$x] = $r['value']; + } + } elseif (!is_array($operand1)) { + // Operand 1 is a scalar, Operand 2 is an array + foreach ($operand2 as $x => $operandData) { + $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operand1), ' ', $operation, ' ', $this->showValue($operandData)); + $this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack); + $r = $stack->pop(); + $result[$x] = $r['value']; + } + } else { + // Operand 1 and Operand 2 are both arrays + if (!$recursingArrays) { + self::checkMatrixOperands($operand1, $operand2, 2); + } + foreach ($operand1 as $x => $operandData) { + $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2[$x])); + $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2[$x], $operation, $stack, true); + $r = $stack->pop(); + $result[$x] = $r['value']; + } + } + // Log the result details + $this->debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->showTypeDetails($result)); + // And push the result onto the stack + $stack->push('Array', $result); + + return $result; + } + /** * @param null|string $cellID * @param mixed $operand1 @@ -4818,38 +4862,7 @@ class Calculation { // If we're dealing with matrix operations, we want a matrix result if ((is_array($operand1)) || (is_array($operand2))) { - $result = []; - if ((is_array($operand1)) && (!is_array($operand2))) { - foreach ($operand1 as $x => $operandData) { - $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2)); - $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2, $operation, $stack); - $r = $stack->pop(); - $result[$x] = $r['value']; - } - } elseif ((!is_array($operand1)) && (is_array($operand2))) { - foreach ($operand2 as $x => $operandData) { - $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operand1), ' ', $operation, ' ', $this->showValue($operandData)); - $this->executeBinaryComparisonOperation($cellID, $operand1, $operandData, $operation, $stack); - $r = $stack->pop(); - $result[$x] = $r['value']; - } - } else { - if (!$recursingArrays) { - self::checkMatrixOperands($operand1, $operand2, 2); - } - foreach ($operand1 as $x => $operandData) { - $this->debugLog->writeDebugLog('Evaluating Comparison ', $this->showValue($operandData), ' ', $operation, ' ', $this->showValue($operand2[$x])); - $this->executeBinaryComparisonOperation($cellID, $operandData, $operand2[$x], $operation, $stack, true); - $r = $stack->pop(); - $result[$x] = $r['value']; - } - } - // Log the result details - $this->debugLog->writeDebugLog('Comparison Evaluation Result is ', $this->showTypeDetails($result)); - // And push the result onto the stack - $stack->push('Array', $result); - - return $result; + return $this->executeArrayComparison($cellID, $operand1, $operand2, $operation, $stack, $recursingArrays); } // Simple validate the two operands if they are string values @@ -4863,10 +4876,10 @@ class Calculation // Use case insensitive comparaison if not OpenOffice mode if (Functions::getCompatibilityMode() != Functions::COMPATIBILITY_OPENOFFICE) { if (is_string($operand1)) { - $operand1 = strtoupper($operand1); + $operand1 = Shared\StringHelper::strToUpper($operand1); } if (is_string($operand2)) { - $operand2 = strtoupper($operand2); + $operand2 = Shared\StringHelper::strToUpper($operand2); } } diff --git a/src/PhpSpreadsheet/Calculation/Logical/Conditional.php b/src/PhpSpreadsheet/Calculation/Logical/Conditional.php index 12256d34..e84d0f33 100644 --- a/src/PhpSpreadsheet/Calculation/Logical/Conditional.php +++ b/src/PhpSpreadsheet/Calculation/Logical/Conditional.php @@ -83,11 +83,11 @@ class Conditional $targetValue = Functions::flattenSingleValue($arguments[0]); $argc = count($arguments) - 1; $switchCount = floor($argc / 2); - $switchSatisfied = false; $hasDefaultClause = $argc % 2 !== 0; - $defaultClause = $argc % 2 === 0 ? null : $arguments[count($arguments) - 1]; + $defaultClause = $argc % 2 === 0 ? null : $arguments[$argc]; - if ($switchCount) { + $switchSatisfied = false; + if ($switchCount > 0) { for ($index = 0; $index < $switchCount; ++$index) { if ($targetValue == $arguments[$index * 2 + 1]) { $result = $arguments[$index * 2 + 2]; @@ -98,7 +98,7 @@ class Conditional } } - if (!$switchSatisfied) { + if ($switchSatisfied !== true) { $result = $hasDefaultClause ? $defaultClause : Functions::NA(); } } @@ -161,12 +161,14 @@ class Conditional */ public static function IFS(...$arguments) { - if (count($arguments) % 2 != 0) { + $argumentCount = count($arguments); + + if ($argumentCount % 2 != 0) { return Functions::NA(); } // We use instance of Exception as a falseValue in order to prevent string collision with value in cell $falseValueException = new Exception(); - for ($i = 0; $i < count($arguments); $i += 2) { + for ($i = 0; $i < $argumentCount; $i += 2) { $testValue = ($arguments[$i] === null) ? '' : Functions::flattenSingleValue($arguments[$i]); $returnIfTrue = ($arguments[$i + 1] === null) ? '' : Functions::flattenSingleValue($arguments[$i + 1]); $result = self::statementIf($testValue, $returnIfTrue, $falseValueException); diff --git a/src/PhpSpreadsheet/Cell/Coordinate.php b/src/PhpSpreadsheet/Cell/Coordinate.php index 2afeebe9..8d81f3a1 100644 --- a/src/PhpSpreadsheet/Cell/Coordinate.php +++ b/src/PhpSpreadsheet/Cell/Coordinate.php @@ -339,7 +339,8 @@ abstract class Coordinate private static function processRangeSetOperators(array $operators, array $cells): array { - for ($offset = 0; $offset < count($operators); ++$offset) { + $operatorCount = count($operators); + for ($offset = 0; $offset < $operatorCount; ++$offset) { $operator = $operators[$offset]; if ($operator !== ' ') { continue; @@ -350,6 +351,7 @@ abstract class Coordinate $operators = array_values($operators); $cells = array_values($cells); --$offset; + --$operatorCount; } return $cells; diff --git a/src/PhpSpreadsheet/Document/Properties.php b/src/PhpSpreadsheet/Document/Properties.php index 0876a9ed..d6aff81e 100644 --- a/src/PhpSpreadsheet/Document/Properties.php +++ b/src/PhpSpreadsheet/Document/Properties.php @@ -506,49 +506,33 @@ class Properties switch ($propertyType) { case 'empty': // Empty return ''; - - break; case 'null': // Null return null; - - break; case 'i1': // 1-Byte Signed Integer case 'i2': // 2-Byte Signed Integer case 'i4': // 4-Byte Signed Integer case 'i8': // 8-Byte Signed Integer case 'int': // Integer return (int) $propertyValue; - - break; case 'ui1': // 1-Byte Unsigned Integer case 'ui2': // 2-Byte Unsigned Integer case 'ui4': // 4-Byte Unsigned Integer case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return abs((int) $propertyValue); - - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return (float) $propertyValue; - - break; case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return $propertyValue; - - break; case 'date': // Date and Time case 'filetime': // File Time return strtotime($propertyValue); - - break; case 'bool': // Boolean return $propertyValue == 'true'; - - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -563,8 +547,6 @@ class Properties case 'clsid': // Class ID case 'cf': // Clipboard Data return $propertyValue; - - break; } return $propertyValue; @@ -584,31 +566,21 @@ class Properties case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return self::PROPERTY_TYPE_INTEGER; - - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return self::PROPERTY_TYPE_FLOAT; - - break; case 'empty': // Empty case 'null': // Null case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return self::PROPERTY_TYPE_STRING; - - break; case 'date': // Date and Time case 'filetime': // File Time return self::PROPERTY_TYPE_DATE; - - break; case 'bool': // Boolean return self::PROPERTY_TYPE_BOOLEAN; - - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -623,8 +595,6 @@ class Properties case 'clsid': // Class ID case 'cf': // Clipboard Data return self::PROPERTY_TYPE_UNKNOWN; - - break; } return self::PROPERTY_TYPE_UNKNOWN; From ae2468426fd77769cfdd0ea01595d6c28e911425 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 15 Mar 2021 14:14:44 +0100 Subject: [PATCH 118/187] jpgraph seems to be finally dying with PHP. (#1926) * jpgraph seems to be finally dying with PHP. Until we have a valid alternative, disabling this run for PHP because it errors https://github.com/HuasoFoundries/jpgraph looks like a natural successor, but it isn't BC so it will require some work to integrate --- samples/Chart/35_Chart_render.php | 5 +++++ tests/PhpSpreadsheetTests/Helper/SampleTest.php | 1 + 2 files changed, 6 insertions(+) diff --git a/samples/Chart/35_Chart_render.php b/samples/Chart/35_Chart_render.php index 9638c679..ebab16a7 100644 --- a/samples/Chart/35_Chart_render.php +++ b/samples/Chart/35_Chart_render.php @@ -5,6 +5,11 @@ use PhpOffice\PhpSpreadsheet\Settings; require __DIR__ . '/../Header.php'; +if (PHP_VERSION_ID >= 80000) { + $helper->log('Jpgraph no longer runs against PHP8'); + exit; +} + // Change these values to select the Rendering library that you wish to use Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\JpGraph::class); diff --git a/tests/PhpSpreadsheetTests/Helper/SampleTest.php b/tests/PhpSpreadsheetTests/Helper/SampleTest.php index cd87eda2..a604bcfc 100644 --- a/tests/PhpSpreadsheetTests/Helper/SampleTest.php +++ b/tests/PhpSpreadsheetTests/Helper/SampleTest.php @@ -30,6 +30,7 @@ class SampleTest extends TestCase $skipped = [ 'Chart/32_Chart_read_write_PDF.php', // Unfortunately JpGraph is not up to date for latest PHP and raise many warnings 'Chart/32_Chart_read_write_HTML.php', // idem + 'Chart/35_Chart_render.php', // idem ]; // TCPDF and DomPDF libraries don't support PHP8 yet if (\PHP_VERSION_ID >= 80000) { From 09022256f4b6095c51c77e1187b0a2d32efbca0d Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 15 Mar 2021 14:50:05 +0100 Subject: [PATCH 119/187] Resolve Deprecated setMethods() call when Mocking for tests (#1925) Resolve Deprecated `setMethods()` calls when Mocking for tests, using `onlyMethods()` and `addMethods()` instead --- .../Functions/LookupRef/ColumnTest.php | 2 +- .../Functions/LookupRef/RowTest.php | 2 +- .../Functions/MathTrig/SubTotalTest.php | 22 +++++++++---------- .../Cell/AdvancedValueBinderTest.php | 15 ++++++++----- .../Collection/CellsTest.php | 2 +- .../PhpSpreadsheetTests/Helper/SampleTest.php | 2 +- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php index 363c6c1b..61c7d40d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php @@ -34,7 +34,7 @@ class ColumnTest extends TestCase public function testCOLUMNwithNull(): void { $cell = $this->getMockBuilder(Cell::class) - ->setMethods(['getColumn']) + ->onlyMethods(['getColumn']) ->disableOriginalConstructor() ->getMock(); $cell->method('getColumn') diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php index 804b924d..29a72a28 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php @@ -34,7 +34,7 @@ class RowTest extends TestCase public function testROWwithNull(): void { $cell = $this->getMockBuilder(Cell::class) - ->setMethods(['getRow']) + ->onlyMethods(['getRow']) ->disableOriginalConstructor() ->getMock(); $cell->method('getRow') diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php index efee60bd..a629a7f4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php @@ -25,7 +25,7 @@ class SubTotalTest extends TestCase public function testSUBTOTAL($expectedResult, ...$args): void { $cell = $this->getMockBuilder(Cell::class) - ->setMethods(['getValue', 'isFormula']) + ->onlyMethods(['getValue', 'isFormula']) ->disableOriginalConstructor() ->getMock(); $cell->method('getValue') @@ -33,7 +33,7 @@ class SubTotalTest extends TestCase $cell->method('getValue') ->willReturn(false); $worksheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['cellExists', 'getCell']) + ->onlyMethods(['cellExists', 'getCell']) ->disableOriginalConstructor() ->getMock(); $worksheet->method('cellExists') @@ -41,7 +41,7 @@ class SubTotalTest extends TestCase $worksheet->method('getCell') ->willReturn($cell); $cellReference = $this->getMockBuilder(Cell::class) - ->setMethods(['getWorksheet']) + ->onlyMethods(['getWorksheet']) ->disableOriginalConstructor() ->getMock(); $cellReference->method('getWorksheet') @@ -75,7 +75,7 @@ class SubTotalTest extends TestCase $visibilityGenerator = $this->rowVisibility($hiddenRows); $rowDimension = $this->getMockBuilder(RowDimension::class) - ->setMethods(['getVisible']) + ->onlyMethods(['getVisible']) ->disableOriginalConstructor() ->getMock(); $rowDimension->method('getVisible') @@ -86,13 +86,13 @@ class SubTotalTest extends TestCase return $result; }); $columnDimension = $this->getMockBuilder(ColumnDimension::class) - ->setMethods(['getVisible']) + ->onlyMethods(['getVisible']) ->disableOriginalConstructor() ->getMock(); $columnDimension->method('getVisible') ->willReturn(true); $cell = $this->getMockBuilder(Cell::class) - ->setMethods(['getValue', 'isFormula']) + ->onlyMethods(['getValue', 'isFormula']) ->disableOriginalConstructor() ->getMock(); $cell->method('getValue') @@ -100,7 +100,7 @@ class SubTotalTest extends TestCase $cell->method('getValue') ->willReturn(false); $worksheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['cellExists', 'getCell', 'getRowDimension', 'getColumnDimension']) + ->onlyMethods(['cellExists', 'getCell', 'getRowDimension', 'getColumnDimension']) ->disableOriginalConstructor() ->getMock(); $worksheet->method('cellExists') @@ -112,7 +112,7 @@ class SubTotalTest extends TestCase $worksheet->method('getColumnDimension') ->willReturn($columnDimension); $cellReference = $this->getMockBuilder(Cell::class) - ->setMethods(['getWorksheet']) + ->onlyMethods(['getWorksheet']) ->disableOriginalConstructor() ->getMock(); $cellReference->method('getWorksheet') @@ -153,7 +153,7 @@ class SubTotalTest extends TestCase $cellIsFormulaGenerator = $this->cellIsFormula(Functions::flattenArray(array_slice($args, 1))); $cell = $this->getMockBuilder(Cell::class) - ->setMethods(['getValue', 'isFormula']) + ->onlyMethods(['getValue', 'isFormula']) ->disableOriginalConstructor() ->getMock(); $cell->method('getValue') @@ -171,7 +171,7 @@ class SubTotalTest extends TestCase return $result; }); $worksheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['cellExists', 'getCell']) + ->onlyMethods(['cellExists', 'getCell']) ->disableOriginalConstructor() ->getMock(); $worksheet->method('cellExists') @@ -179,7 +179,7 @@ class SubTotalTest extends TestCase $worksheet->method('getCell') ->willReturn($cell); $cellReference = $this->getMockBuilder(Cell::class) - ->setMethods(['getWorksheet']) + ->onlyMethods(['getWorksheet']) ->disableOriginalConstructor() ->getMock(); $cellReference->method('getWorksheet') diff --git a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php index eefa7b83..e71e3ad2 100644 --- a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php @@ -46,7 +46,8 @@ class AdvancedValueBinderTest extends TestCase public function testCurrency($value, $valueBinded, $format, $thousandsSeparator, $decimalSeparator, $currencyCode): void { $sheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->onlyMethods(['getStyle', 'getCellCollection']) + ->addMethods(['getNumberFormat', 'setFormatCode']) ->getMock(); $cellCollection = $this->getMockBuilder(Cells::class) ->disableOriginalConstructor() @@ -106,7 +107,8 @@ class AdvancedValueBinderTest extends TestCase public function testFractions($value, $valueBinded, $format): void { $sheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->onlyMethods(['getStyle', 'getCellCollection']) + ->addMethods(['getNumberFormat', 'setFormatCode']) ->getMock(); $cellCollection = $this->getMockBuilder(Cells::class) @@ -164,7 +166,8 @@ class AdvancedValueBinderTest extends TestCase public function testPercentages($value, $valueBinded, $format): void { $sheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->onlyMethods(['getStyle', 'getCellCollection']) + ->addMethods(['getNumberFormat', 'setFormatCode']) ->getMock(); $cellCollection = $this->getMockBuilder(Cells::class) ->disableOriginalConstructor() @@ -214,7 +217,8 @@ class AdvancedValueBinderTest extends TestCase public function testTimes($value, $valueBinded, $format): void { $sheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['getStyle', 'getNumberFormat', 'setFormatCode', 'getCellCollection']) + ->onlyMethods(['getStyle', 'getCellCollection']) + ->addMethods(['getNumberFormat', 'setFormatCode']) ->getMock(); $cellCollection = $this->getMockBuilder(Cells::class) @@ -265,7 +269,8 @@ class AdvancedValueBinderTest extends TestCase public function testStringWrapping(string $value, bool $wrapped): void { $sheet = $this->getMockBuilder(Worksheet::class) - ->setMethods(['getStyle', 'getAlignment', 'setWrapText', 'getCellCollection']) + ->onlyMethods(['getStyle', 'getCellCollection']) + ->addMethods(['getAlignment', 'setWrapText']) ->getMock(); $cellCollection = $this->getMockBuilder(Cells::class) ->disableOriginalConstructor() diff --git a/tests/PhpSpreadsheetTests/Collection/CellsTest.php b/tests/PhpSpreadsheetTests/Collection/CellsTest.php index 539d0232..5e656cf5 100644 --- a/tests/PhpSpreadsheetTests/Collection/CellsTest.php +++ b/tests/PhpSpreadsheetTests/Collection/CellsTest.php @@ -91,7 +91,7 @@ class CellsTest extends TestCase $collection = $this->getMockBuilder(Cells::class) ->setConstructorArgs([new Worksheet(), new Memory()]) - ->setMethods(['has']) + ->onlyMethods(['has']) ->getMock(); $collection->method('has') diff --git a/tests/PhpSpreadsheetTests/Helper/SampleTest.php b/tests/PhpSpreadsheetTests/Helper/SampleTest.php index a604bcfc..8956771c 100644 --- a/tests/PhpSpreadsheetTests/Helper/SampleTest.php +++ b/tests/PhpSpreadsheetTests/Helper/SampleTest.php @@ -30,7 +30,6 @@ class SampleTest extends TestCase $skipped = [ 'Chart/32_Chart_read_write_PDF.php', // Unfortunately JpGraph is not up to date for latest PHP and raise many warnings 'Chart/32_Chart_read_write_HTML.php', // idem - 'Chart/35_Chart_render.php', // idem ]; // TCPDF and DomPDF libraries don't support PHP8 yet if (\PHP_VERSION_ID >= 80000) { @@ -39,6 +38,7 @@ class SampleTest extends TestCase [ 'Pdf/21_Pdf_Domdf.php', 'Pdf/21_Pdf_TCPDF.php', + 'Chart/35_Chart_render.php', // idem ] ); } From 9b67e3f5979835ad2da4f6c6c0cb1d84ad58d18e Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 15 Mar 2021 23:02:41 +0100 Subject: [PATCH 120/187] Fix error with a single byte being removed after the _ spacing character when rendering number formats (#1927) * Fix error with a single byte being removed after the _ spacing character when rendering number formats --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Style/NumberFormat.php | 4 ++-- tests/data/Style/NumberFormat.php | 9 +++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2565a768..86be590b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fixed issue with _ spacing character in number format mask corrumpting output from toFormattedString() [Issue 1924#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1924) [PR #1927](https://github.com/PHPOffice/PhpSpreadsheet/pull/1927) - Fix for [Issue #1887](https://github.com/PHPOffice/PhpSpreadsheet/issues/1887) - Lose Track of Selected Cells After Save - Fixed issue with Xlsx@listWorksheetInfo not returning any data - Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640) diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index a623657b..3c6985a2 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -848,7 +848,7 @@ class NumberFormat extends Supervisor ); // Convert any other escaped characters to quoted strings, e.g. (\T to "T") - $format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/u', '"${2}"', $format); + $format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/ui', '"${2}"', $format); // Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal) $sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format); @@ -857,7 +857,7 @@ class NumberFormat extends Supervisor // In Excel formats, "_" is used to add spacing, // The following character indicates the size of the spacing, which we can't do in HTML, so we just use a standard space - $format = preg_replace('/_./', ' ', $format); + $format = preg_replace('/_(.)/ui', ' ${1}', $format); // Let's begin inspecting the format and converting the value to a formatted string diff --git a/tests/data/Style/NumberFormat.php b/tests/data/Style/NumberFormat.php index 81bb90ae..db14b0e1 100644 --- a/tests/data/Style/NumberFormat.php +++ b/tests/data/Style/NumberFormat.php @@ -128,6 +128,11 @@ return [ 12345.678900000001, '#,##0.000\ [$]', ], + 'Spacing Character' => [ + '826.00 €', + 826, + '#,##0.00 _€', + ], [ '5.68', 5.6788999999999996, @@ -294,12 +299,12 @@ return [ '[$-1010409]#,##0.00;-#,##0.00', ], [ - ' $ 23.06 ', + ' ($ 23.06 )', 23.0597, '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)', ], [ - ' € 13.03 ', + ' (€ 13.03 )', 13.0316, '_("€"* #,##0.00_);_("€"* \(#,##0.00\);_("€"* "-"??_);_(@_)', ], From 6490c3ff0ae10b0e2e7649c119c186dcb3df28bf Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 17 Mar 2021 12:18:34 +0100 Subject: [PATCH 121/187] First step in some refactoring of the NumberFormat class (#1928) * Refactoring of the NumberFormat class; separate the cell numberformat properties from the actually code used to format a value, leaving just a callthrough stub * Resolve issue with percentage formatter, and provide support for ? placeholders in percentage formatting --- src/PhpSpreadsheet/Style/NumberFormat.php | 490 +----------------- .../Style/NumberFormat/BaseFormatter.php | 12 + .../Style/NumberFormat/DateFormatter.php | 129 +++++ .../Style/NumberFormat/Formatter.php | 162 ++++++ .../Style/NumberFormat/FractionFormatter.php | 45 ++ .../Style/NumberFormat/NumberFormatter.php | 181 +++++++ .../NumberFormat/PercentageFormatter.php | 42 ++ tests/data/Style/NumberFormat.php | 75 +++ 8 files changed, 647 insertions(+), 489 deletions(-) create mode 100644 src/PhpSpreadsheet/Style/NumberFormat/BaseFormatter.php create mode 100644 src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php create mode 100644 src/PhpSpreadsheet/Style/NumberFormat/Formatter.php create mode 100644 src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php create mode 100644 src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php create mode 100644 src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index 3c6985a2..b5cc05f4 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -2,10 +2,6 @@ namespace PhpOffice\PhpSpreadsheet\Style; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PhpOffice\PhpSpreadsheet\Shared\StringHelper; - class NumberFormat extends Supervisor { // Pre-defined formats @@ -389,434 +385,6 @@ class NumberFormat extends Supervisor ); } - /** - * Search/replace values to convert Excel date/time format masks to PHP format masks. - * - * @var array - */ - private static $dateFormatReplacements = [ - // first remove escapes related to non-format characters - '\\' => '', - // 12-hour suffix - 'am/pm' => 'A', - // 4-digit year - 'e' => 'Y', - 'yyyy' => 'Y', - // 2-digit year - 'yy' => 'y', - // first letter of month - no php equivalent - 'mmmmm' => 'M', - // full month name - 'mmmm' => 'F', - // short month name - 'mmm' => 'M', - // mm is minutes if time, but can also be month w/leading zero - // so we try to identify times be the inclusion of a : separator in the mask - // It isn't perfect, but the best way I know how - ':mm' => ':i', - 'mm:' => 'i:', - // month leading zero - 'mm' => 'm', - // month no leading zero - 'm' => 'n', - // full day of week name - 'dddd' => 'l', - // short day of week name - 'ddd' => 'D', - // days leading zero - 'dd' => 'd', - // days no leading zero - 'd' => 'j', - // seconds - 'ss' => 's', - // fractional seconds - no php equivalent - '.s' => '', - ]; - - /** - * Search/replace values to convert Excel date/time format masks hours to PHP format masks (24 hr clock). - * - * @var array - */ - private static $dateFormatReplacements24 = [ - 'hh' => 'H', - 'h' => 'G', - ]; - - /** - * Search/replace values to convert Excel date/time format masks hours to PHP format masks (12 hr clock). - * - * @var array - */ - private static $dateFormatReplacements12 = [ - 'hh' => 'h', - 'h' => 'g', - ]; - - private static function setLowercaseCallback($matches) - { - return mb_strtolower($matches[0]); - } - - private static function escapeQuotesCallback($matches) - { - return '\\' . implode('\\', str_split($matches[1])); - } - - private static function formatAsDate(&$value, &$format): void - { - // strip off first part containing e.g. [$-F800] or [$USD-409] - // general syntax: [$-] - // language info is in hexadecimal - // strip off chinese part like [DBNum1][$-804] - $format = preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format); - - // OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case; - // but we don't want to change any quoted strings - $format = preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', ['self', 'setLowercaseCallback'], $format); - - // Only process the non-quoted blocks for date format characters - $blocks = explode('"', $format); - foreach ($blocks as $key => &$block) { - if ($key % 2 == 0) { - $block = strtr($block, self::$dateFormatReplacements); - if (!strpos($block, 'A')) { - // 24-hour time format - // when [h]:mm format, the [h] should replace to the hours of the value * 24 - if (false !== strpos($block, '[h]')) { - $hours = (int) ($value * 24); - $block = str_replace('[h]', $hours, $block); - - continue; - } - $block = strtr($block, self::$dateFormatReplacements24); - } else { - // 12-hour time format - $block = strtr($block, self::$dateFormatReplacements12); - } - } - } - $format = implode('"', $blocks); - - // escape any quoted characters so that DateTime format() will render them correctly - $format = preg_replace_callback('/"(.*)"/U', ['self', 'escapeQuotesCallback'], $format); - - $dateObj = Date::excelToDateTimeObject($value); - // If the colon preceding minute had been quoted, as happens in - // Excel 2003 XML formats, m will not have been changed to i above. - // Change it now. - $format = \preg_replace('/\\\\:m/', ':i', $format); - $value = $dateObj->format($format); - } - - private static function formatAsPercentage(&$value, &$format): void - { - if ($format === self::FORMAT_PERCENTAGE) { - $value = round((100 * $value), 0) . '%'; - } else { - if (preg_match('/\.[#0]+/', $format, $m)) { - $s = substr($m[0], 0, 1) . (strlen($m[0]) - 1); - $format = str_replace($m[0], $s, $format); - } - if (preg_match('/^[#0]+/', $format, $m)) { - $format = str_replace($m[0], strlen($m[0]), $format); - } - $format = '%' . str_replace('%', 'f%%', $format); - - $value = sprintf($format, 100 * $value); - } - } - - private static function formatAsFraction(&$value, &$format): void - { - $sign = ($value < 0) ? '-' : ''; - - $integerPart = floor(abs($value)); - $decimalPart = trim(fmod(abs($value), 1), '0.'); - $decimalLength = strlen($decimalPart); - $decimalDivisor = 10 ** $decimalLength; - - $GCD = MathTrig::GCD($decimalPart, $decimalDivisor); - - $adjustedDecimalPart = $decimalPart / $GCD; - $adjustedDecimalDivisor = $decimalDivisor / $GCD; - - if ((strpos($format, '0') !== false)) { - $value = "$sign$integerPart $adjustedDecimalPart/$adjustedDecimalDivisor"; - } elseif ((strpos($format, '#') !== false)) { - if ($integerPart == 0) { - $value = "$sign$adjustedDecimalPart/$adjustedDecimalDivisor"; - } else { - $value = "$sign$integerPart $adjustedDecimalPart/$adjustedDecimalDivisor"; - } - } elseif ((substr($format, 0, 3) == '? ?')) { - if ($integerPart == 0) { - $integerPart = ''; - } - $value = "$sign$integerPart $adjustedDecimalPart/$adjustedDecimalDivisor"; - } else { - $adjustedDecimalPart += $integerPart * $adjustedDecimalDivisor; - $value = "$sign$adjustedDecimalPart/$adjustedDecimalDivisor"; - } - } - - private static function mergeComplexNumberFormatMasks($numbers, $masks) - { - $decimalCount = strlen($numbers[1]); - $postDecimalMasks = []; - - do { - $tempMask = array_pop($masks); - if ($tempMask !== null) { - $postDecimalMasks[] = $tempMask; - $decimalCount -= strlen($tempMask); - } - } while ($tempMask !== null && $decimalCount > 0); - - return [ - implode('.', $masks), - implode('.', array_reverse($postDecimalMasks)), - ]; - } - - private static function processComplexNumberFormatMask($number, $mask) - { - $result = $number; - $maskingBlockCount = preg_match_all('/0+/', $mask, $maskingBlocks, PREG_OFFSET_CAPTURE); - - if ($maskingBlockCount > 1) { - $maskingBlocks = array_reverse($maskingBlocks[0]); - - foreach ($maskingBlocks as $block) { - $divisor = 1 . $block[0]; - $size = strlen($block[0]); - $offset = $block[1]; - - $blockValue = sprintf( - '%0' . $size . 'd', - fmod($number, $divisor) - ); - $number = floor($number / $divisor); - $mask = substr_replace($mask, $blockValue, $offset, $size); - } - if ($number > 0) { - $mask = substr_replace($mask, $number, $offset, 0); - } - $result = $mask; - } - - return $result; - } - - private static function complexNumberFormatMask($number, $mask, $splitOnPoint = true) - { - $sign = ($number < 0.0); - $number = abs($number); - - if ($splitOnPoint && strpos($mask, '.') !== false && strpos($number, '.') !== false) { - $numbers = explode('.', $number); - $masks = explode('.', $mask); - if (count($masks) > 2) { - $masks = self::mergeComplexNumberFormatMasks($numbers, $masks); - } - $result1 = self::complexNumberFormatMask($numbers[0], $masks[0], false); - $result2 = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1]), false)); - - return (($sign) ? '-' : '') . $result1 . '.' . $result2; - } - - $result = self::processComplexNumberFormatMask($number, $mask); - - return (($sign) ? '-' : '') . $result; - } - - private static function formatStraightNumericValue($value, $format, array $matches, $useThousands, $number_regex) - { - $left = $matches[1]; - $dec = $matches[2]; - $right = $matches[3]; - - // minimun width of formatted number (including dot) - $minWidth = strlen($left) + strlen($dec) + strlen($right); - if ($useThousands) { - $value = number_format( - $value, - strlen($right), - StringHelper::getDecimalSeparator(), - StringHelper::getThousandsSeparator() - ); - $value = preg_replace($number_regex, $value, $format); - } else { - if (preg_match('/[0#]E[+-]0/i', $format)) { - // Scientific format - $value = sprintf('%5.2E', $value); - } elseif (preg_match('/0([^\d\.]+)0/', $format) || substr_count($format, '.') > 1) { - if ($value == (int) $value && substr_count($format, '.') === 1) { - $value *= 10 ** strlen(explode('.', $format)[1]); - } - $value = self::complexNumberFormatMask($value, $format); - } else { - $sprintf_pattern = "%0$minWidth." . strlen($right) . 'f'; - $value = sprintf($sprintf_pattern, $value); - $value = preg_replace($number_regex, $value, $format); - } - } - - return $value; - } - - private static function formatAsNumber($value, $format) - { - // The "_" in this string has already been stripped out, - // so this test is never true. Furthermore, testing - // on Excel shows this format uses Euro symbol, not "EUR". - //if ($format === self::FORMAT_CURRENCY_EUR_SIMPLE) { - // return 'EUR ' . sprintf('%1.2f', $value); - //} - - // Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols - $format = str_replace(['"', '*'], '', $format); - - // Find out if we need thousands separator - // This is indicated by a comma enclosed by a digit placeholder: - // #,# or 0,0 - $useThousands = preg_match('/(#,#|0,0)/', $format); - if ($useThousands) { - $format = preg_replace('/0,0/', '00', $format); - $format = preg_replace('/#,#/', '##', $format); - } - - // Scale thousands, millions,... - // This is indicated by a number of commas after a digit placeholder: - // #, or 0.0,, - $scale = 1; // same as no scale - $matches = []; - if (preg_match('/(#|0)(,+)/', $format, $matches)) { - $scale = 1000 ** strlen($matches[2]); - - // strip the commas - $format = preg_replace('/0,+/', '0', $format); - $format = preg_replace('/#,+/', '#', $format); - } - - if (preg_match('/#?.*\?\/\?/', $format, $m)) { - if ($value != (int) $value) { - self::formatAsFraction($value, $format); - } - } else { - // Handle the number itself - - // scale number - $value = $value / $scale; - // Strip # - $format = preg_replace('/\\#/', '0', $format); - // Remove locale code [$-###] - $format = preg_replace('/\[\$\-.*\]/', '', $format); - - $n = '/\\[[^\\]]+\\]/'; - $m = preg_replace($n, '', $format); - $number_regex = '/(0+)(\\.?)(0*)/'; - if (preg_match($number_regex, $m, $matches)) { - $value = self::formatStraightNumericValue($value, $format, $matches, $useThousands, $number_regex); - } - } - - if (preg_match('/\[\$(.*)\]/u', $format, $m)) { - // Currency or Accounting - $currencyCode = $m[1]; - [$currencyCode] = explode('-', $currencyCode); - if ($currencyCode == '') { - $currencyCode = StringHelper::getCurrencyCode(); - } - $value = preg_replace('/\[\$([^\]]*)\]/u', $currencyCode, $value); - } - - return $value; - } - - private static function splitFormatCompare($value, $cond, $val, $dfcond, $dfval) - { - if (!$cond) { - $cond = $dfcond; - $val = $dfval; - } - switch ($cond) { - case '>': - return $value > $val; - - case '<': - return $value < $val; - - case '<=': - return $value <= $val; - - case '<>': - return $value != $val; - - case '=': - return $value == $val; - } - - return $value >= $val; - } - - private static function splitFormat($sections, $value) - { - // Extract the relevant section depending on whether number is positive, negative, or zero? - // Text not supported yet. - // Here is how the sections apply to various values in Excel: - // 1 section: [POSITIVE/NEGATIVE/ZERO/TEXT] - // 2 sections: [POSITIVE/ZERO/TEXT] [NEGATIVE] - // 3 sections: [POSITIVE/TEXT] [NEGATIVE] [ZERO] - // 4 sections: [POSITIVE] [NEGATIVE] [ZERO] [TEXT] - $cnt = count($sections); - $color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . ')\\]/'; - $cond_regex = '/\\[(>|>=|<|<=|=|<>)([+-]?\\d+([.]\\d+)?)\\]/'; - $colors = ['', '', '', '', '']; - $condops = ['', '', '', '', '']; - $condvals = [0, 0, 0, 0, 0]; - for ($idx = 0; $idx < $cnt; ++$idx) { - if (preg_match($color_regex, $sections[$idx], $matches)) { - $colors[$idx] = $matches[0]; - $sections[$idx] = preg_replace($color_regex, '', $sections[$idx]); - } - if (preg_match($cond_regex, $sections[$idx], $matches)) { - $condops[$idx] = $matches[1]; - $condvals[$idx] = $matches[2]; - $sections[$idx] = preg_replace($cond_regex, '', $sections[$idx]); - } - } - $color = $colors[0]; - $format = $sections[0]; - $absval = $value; - switch ($cnt) { - case 2: - $absval = abs($value); - if (!self::splitFormatCompare($value, $condops[0], $condvals[0], '>=', 0)) { - $color = $colors[1]; - $format = $sections[1]; - } - - break; - case 3: - case 4: - $absval = abs($value); - if (!self::splitFormatCompare($value, $condops[0], $condvals[0], '>', 0)) { - if (self::splitFormatCompare($value, $condops[1], $condvals[1], '<', 0)) { - $color = $colors[1]; - $format = $sections[1]; - } else { - $color = $colors[2]; - $format = $sections[2]; - } - } - - break; - } - - return [$color, $format, $absval]; - } - /** * Convert a value in a pre-defined format to a PHP string. * @@ -828,63 +396,7 @@ class NumberFormat extends Supervisor */ public static function toFormattedString($value, $format, $callBack = null) { - // For now we do not treat strings although section 4 of a format code affects strings - if (!is_numeric($value)) { - return $value; - } - - // For 'General' format code, we just pass the value although this is not entirely the way Excel does it, - // it seems to round numbers to a total of 10 digits. - if (($format === self::FORMAT_GENERAL) || ($format === self::FORMAT_TEXT)) { - return $value; - } - - $format = preg_replace_callback( - '/(["])(?:(?=(\\\\?))\\2.)*?\\1/u', - function ($matches) { - return str_replace('.', chr(0x00), $matches[0]); - }, - $format - ); - - // Convert any other escaped characters to quoted strings, e.g. (\T to "T") - $format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/ui', '"${2}"', $format); - - // Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal) - $sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format); - - [$colors, $format, $value] = self::splitFormat($sections, $value); - - // In Excel formats, "_" is used to add spacing, - // The following character indicates the size of the spacing, which we can't do in HTML, so we just use a standard space - $format = preg_replace('/_(.)/ui', ' ${1}', $format); - - // Let's begin inspecting the format and converting the value to a formatted string - - // Check for date/time characters (not inside quotes) - if (preg_match('/(\[\$[A-Z]*-[0-9A-F]*\])*[hmsdy](?=(?:[^"]|"[^"]*")*$)/miu', $format, $matches)) { - // datetime format - self::formatAsDate($value, $format); - } else { - if (substr($format, 0, 1) === '"' && substr($format, -1, 1) === '"') { - $value = substr($format, 1, -1); - } elseif (preg_match('/%$/', $format)) { - // % number format - self::formatAsPercentage($value, $format); - } else { - $value = self::formatAsNumber($value, $format); - } - } - - // Additional formatting provided by callback function - if ($callBack !== null) { - [$writerInstance, $function] = $callBack; - $value = $writerInstance->$function($value, $colors); - } - - $value = str_replace(chr(0x00), '.', $value); - - return $value; + return NumberFormat\Formatter::toFormattedString($value, $format, $callBack); } protected function exportArray1(): array diff --git a/src/PhpSpreadsheet/Style/NumberFormat/BaseFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/BaseFormatter.php new file mode 100644 index 00000000..7988143c --- /dev/null +++ b/src/PhpSpreadsheet/Style/NumberFormat/BaseFormatter.php @@ -0,0 +1,12 @@ + '', + // 12-hour suffix + 'am/pm' => 'A', + // 4-digit year + 'e' => 'Y', + 'yyyy' => 'Y', + // 2-digit year + 'yy' => 'y', + // first letter of month - no php equivalent + 'mmmmm' => 'M', + // full month name + 'mmmm' => 'F', + // short month name + 'mmm' => 'M', + // mm is minutes if time, but can also be month w/leading zero + // so we try to identify times be the inclusion of a : separator in the mask + // It isn't perfect, but the best way I know how + ':mm' => ':i', + 'mm:' => 'i:', + // month leading zero + 'mm' => 'm', + // month no leading zero + 'm' => 'n', + // full day of week name + 'dddd' => 'l', + // short day of week name + 'ddd' => 'D', + // days leading zero + 'dd' => 'd', + // days no leading zero + 'd' => 'j', + // seconds + 'ss' => 's', + // fractional seconds - no php equivalent + '.s' => '', + ]; + + /** + * Search/replace values to convert Excel date/time format masks hours to PHP format masks (24 hr clock). + * + * @var array + */ + private static $dateFormatReplacements24 = [ + 'hh' => 'H', + 'h' => 'G', + ]; + + /** + * Search/replace values to convert Excel date/time format masks hours to PHP format masks (12 hr clock). + * + * @var array + */ + private static $dateFormatReplacements12 = [ + 'hh' => 'h', + 'h' => 'g', + ]; + + public static function format($value, string $format): string + { + // strip off first part containing e.g. [$-F800] or [$USD-409] + // general syntax: [$-] + // language info is in hexadecimal + // strip off chinese part like [DBNum1][$-804] + $format = preg_replace('/^(\[DBNum\d\])*(\[\$[^\]]*\])/i', '', $format); + + // OpenOffice.org uses upper-case number formats, e.g. 'YYYY', convert to lower-case; + // but we don't want to change any quoted strings + $format = preg_replace_callback('/(?:^|")([^"]*)(?:$|")/', ['self', 'setLowercaseCallback'], $format); + + // Only process the non-quoted blocks for date format characters + $blocks = explode('"', $format); + foreach ($blocks as $key => &$block) { + if ($key % 2 == 0) { + $block = strtr($block, self::$dateFormatReplacements); + if (!strpos($block, 'A')) { + // 24-hour time format + // when [h]:mm format, the [h] should replace to the hours of the value * 24 + if (false !== strpos($block, '[h]')) { + $hours = (int) ($value * 24); + $block = str_replace('[h]', $hours, $block); + + continue; + } + $block = strtr($block, self::$dateFormatReplacements24); + } else { + // 12-hour time format + $block = strtr($block, self::$dateFormatReplacements12); + } + } + } + $format = implode('"', $blocks); + + // escape any quoted characters so that DateTime format() will render them correctly + $format = preg_replace_callback('/"(.*)"/U', ['self', 'escapeQuotesCallback'], $format); + + $dateObj = Date::excelToDateTimeObject($value); + // If the colon preceding minute had been quoted, as happens in + // Excel 2003 XML formats, m will not have been changed to i above. + // Change it now. + $format = \preg_replace('/\\\\:m/', ':i', $format); + + return $dateObj->format($format); + } + + private static function setLowercaseCallback($matches): string + { + return mb_strtolower($matches[0]); + } + + private static function escapeQuotesCallback($matches): string + { + return '\\' . implode('\\', str_split($matches[1])); + } +} diff --git a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php new file mode 100644 index 00000000..6fa43fe2 --- /dev/null +++ b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php @@ -0,0 +1,162 @@ +': + return $value > $val; + + case '<': + return $value < $val; + + case '<=': + return $value <= $val; + + case '<>': + return $value != $val; + + case '=': + return $value == $val; + } + + return $value >= $val; + } + + private static function splitFormat($sections, $value) + { + // Extract the relevant section depending on whether number is positive, negative, or zero? + // Text not supported yet. + // Here is how the sections apply to various values in Excel: + // 1 section: [POSITIVE/NEGATIVE/ZERO/TEXT] + // 2 sections: [POSITIVE/ZERO/TEXT] [NEGATIVE] + // 3 sections: [POSITIVE/TEXT] [NEGATIVE] [ZERO] + // 4 sections: [POSITIVE] [NEGATIVE] [ZERO] [TEXT] + $cnt = count($sections); + $color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . ')\\]/'; + $cond_regex = '/\\[(>|>=|<|<=|=|<>)([+-]?\\d+([.]\\d+)?)\\]/'; + $colors = ['', '', '', '', '']; + $condops = ['', '', '', '', '']; + $condvals = [0, 0, 0, 0, 0]; + for ($idx = 0; $idx < $cnt; ++$idx) { + if (preg_match($color_regex, $sections[$idx], $matches)) { + $colors[$idx] = $matches[0]; + $sections[$idx] = preg_replace($color_regex, '', $sections[$idx]); + } + if (preg_match($cond_regex, $sections[$idx], $matches)) { + $condops[$idx] = $matches[1]; + $condvals[$idx] = $matches[2]; + $sections[$idx] = preg_replace($cond_regex, '', $sections[$idx]); + } + } + $color = $colors[0]; + $format = $sections[0]; + $absval = $value; + switch ($cnt) { + case 2: + $absval = abs($value); + if (!self::splitFormatCompare($value, $condops[0], $condvals[0], '>=', 0)) { + $color = $colors[1]; + $format = $sections[1]; + } + + break; + case 3: + case 4: + $absval = abs($value); + if (!self::splitFormatCompare($value, $condops[0], $condvals[0], '>', 0)) { + if (self::splitFormatCompare($value, $condops[1], $condvals[1], '<', 0)) { + $color = $colors[1]; + $format = $sections[1]; + } else { + $color = $colors[2]; + $format = $sections[2]; + } + } + + break; + } + + return [$color, $format, $absval]; + } + + /** + * Convert a value in a pre-defined format to a PHP string. + * + * @param mixed $value Value to format + * @param string $format Format code, see = NumberFormat::FORMAT_* + * @param array $callBack Callback function for additional formatting of string + * + * @return string Formatted string + */ + public static function toFormattedString($value, $format, $callBack = null) + { + // For now we do not treat strings although section 4 of a format code affects strings + if (!is_numeric($value)) { + return $value; + } + + // For 'General' format code, we just pass the value although this is not entirely the way Excel does it, + // it seems to round numbers to a total of 10 digits. + if (($format === NumberFormat::FORMAT_GENERAL) || ($format === NumberFormat::FORMAT_TEXT)) { + return $value; + } + + $format = preg_replace_callback( + '/(["])(?:(?=(\\\\?))\\2.)*?\\1/u', + function ($matches) { + return str_replace('.', chr(0x00), $matches[0]); + }, + $format + ); + + // Convert any other escaped characters to quoted strings, e.g. (\T to "T") + $format = preg_replace('/(\\\(((.)(?!((AM\/PM)|(A\/P))))|([^ ])))(?=(?:[^"]|"[^"]*")*$)/ui', '"${2}"', $format); + + // Get the sections, there can be up to four sections, separated with a semi-colon (but only if not a quoted literal) + $sections = preg_split('/(;)(?=(?:[^"]|"[^"]*")*$)/u', $format); + + [$colors, $format, $value] = self::splitFormat($sections, $value); + + // In Excel formats, "_" is used to add spacing, + // The following character indicates the size of the spacing, which we can't do in HTML, so we just use a standard space + $format = preg_replace('/_/ui', ' ', $format); + + // Let's begin inspecting the format and converting the value to a formatted string + + // Check for date/time characters (not inside quotes) + if (preg_match('/(\[\$[A-Z]*-[0-9A-F]*\])*[hmsdy](?=(?:[^"]|"[^"]*")*$)/miu', $format, $matches)) { + // datetime format + $value = DateFormatter::format($value, $format); + } else { + if (substr($format, 0, 1) === '"' && substr($format, -1, 1) === '"') { + $value = substr($format, 1, -1); + } elseif (preg_match('/[0#, ]%/', $format)) { + // % number format + $value = PercentageFormatter::format($value, $format); + } else { + $value = NumberFormatter::format($value, $format); + } + } + + // Additional formatting provided by callback function + if ($callBack !== null) { + [$writerInstance, $function] = $callBack; + $value = $writerInstance->$function($value, $colors); + } + + $value = str_replace(chr(0x00), '.', $value); + + return $value; + } +} diff --git a/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php new file mode 100644 index 00000000..2b1c7911 --- /dev/null +++ b/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php @@ -0,0 +1,45 @@ + 0); + + return [ + implode('.', $masks), + implode('.', array_reverse($postDecimalMasks)), + ]; + } + + private static function processComplexNumberFormatMask($number, $mask): string + { + $result = $number; + $maskingBlockCount = preg_match_all('/0+/', $mask, $maskingBlocks, PREG_OFFSET_CAPTURE); + + if ($maskingBlockCount > 1) { + $maskingBlocks = array_reverse($maskingBlocks[0]); + + foreach ($maskingBlocks as $block) { + $size = strlen($block[0]); + $divisor = 10 ** $size; + $offset = $block[1]; + + $blockValue = sprintf("%0{$size}d", fmod($number, $divisor)); + $number = floor($number / $divisor); + $mask = substr_replace($mask, $blockValue, $offset, $size); + } + if ($number > 0) { + $mask = substr_replace($mask, $number, $offset, 0); + } + $result = $mask; + } + + return $result; + } + + private static function complexNumberFormatMask($number, $mask, $splitOnPoint = true): string + { + $sign = ($number < 0.0) ? '-' : ''; + $number = abs($number); + + if ($splitOnPoint && strpos($mask, '.') !== false && strpos($number, '.') !== false) { + $numbers = explode('.', $number); + $masks = explode('.', $mask); + if (count($masks) > 2) { + $masks = self::mergeComplexNumberFormatMasks($numbers, $masks); + } + $integerPart = self::complexNumberFormatMask($numbers[0], $masks[0], false); + $decimalPart = strrev(self::complexNumberFormatMask(strrev($numbers[1]), strrev($masks[1]), false)); + + return "{$sign}{$integerPart}.{$decimalPart}"; + } + + $result = self::processComplexNumberFormatMask($number, $mask); + + return "{$sign}{$result}"; + } + + private static function formatStraightNumericValue($value, $format, array $matches, $useThousands): string + { + $left = $matches[1]; + $dec = $matches[2]; + $right = $matches[3]; + + // minimun width of formatted number (including dot) + $minWidth = strlen($left) + strlen($dec) + strlen($right); + if ($useThousands) { + $value = number_format( + $value, + strlen($right), + StringHelper::getDecimalSeparator(), + StringHelper::getThousandsSeparator() + ); + + return preg_replace(self::NUMBER_REGEX, $value, $format); + } + + if (preg_match('/[0#]E[+-]0/i', $format)) { + // Scientific format + return sprintf('%5.2E', $value); + } elseif (preg_match('/0([^\d\.]+)0/', $format) || substr_count($format, '.') > 1) { + if ($value == (int) $value && substr_count($format, '.') === 1) { + $value *= 10 ** strlen(explode('.', $format)[1]); + } + + return self::complexNumberFormatMask($value, $format); + } + + $sprintf_pattern = "%0$minWidth." . strlen($right) . 'f'; + $value = sprintf($sprintf_pattern, $value); + + return preg_replace(self::NUMBER_REGEX, $value, $format); + } + + public static function format($value, $format): string + { + // The "_" in this string has already been stripped out, + // so this test is never true. Furthermore, testing + // on Excel shows this format uses Euro symbol, not "EUR". + //if ($format === NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE) { + // return 'EUR ' . sprintf('%1.2f', $value); + //} + + // Some non-number strings are quoted, so we'll get rid of the quotes, likewise any positional * symbols + $format = str_replace(['"', '*'], '', $format); + + // Find out if we need thousands separator + // This is indicated by a comma enclosed by a digit placeholder: + // #,# or 0,0 + $useThousands = preg_match('/(#,#|0,0)/', $format); + if ($useThousands) { + $format = preg_replace('/0,0/', '00', $format); + $format = preg_replace('/#,#/', '##', $format); + } + + // Scale thousands, millions,... + // This is indicated by a number of commas after a digit placeholder: + // #, or 0.0,, + $scale = 1; // same as no scale + $matches = []; + if (preg_match('/(#|0)(,+)/', $format, $matches)) { + $scale = 1000 ** strlen($matches[2]); + + // strip the commas + $format = preg_replace('/0,+/', '0', $format); + $format = preg_replace('/#,+/', '#', $format); + } + + if (preg_match('/#?.*\?\/\?/', $format, $m)) { + if ($value != (int) $value) { + $value = FractionFormatter::format($value, $format); + } + } else { + // Handle the number itself + + // scale number + $value = $value / $scale; + // Strip # + $format = preg_replace('/\\#/', '0', $format); + // Remove locale code [$-###] + $format = preg_replace('/\[\$\-.*\]/', '', $format); + + $n = '/\\[[^\\]]+\\]/'; + $m = preg_replace($n, '', $format); + if (preg_match(self::NUMBER_REGEX, $m, $matches)) { + $value = self::formatStraightNumericValue($value, $format, $matches, $useThousands); + } + } + + if (preg_match('/\[\$(.*)\]/u', $format, $m)) { + // Currency or Accounting + $currencyCode = $m[1]; + [$currencyCode] = explode('-', $currencyCode); + if ($currencyCode == '') { + $currencyCode = StringHelper::getCurrencyCode(); + } + $value = preg_replace('/\[\$([^\]]*)\]/u', $currencyCode, $value); + } + + return $value; + } +} diff --git a/src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php new file mode 100644 index 00000000..cf1731ec --- /dev/null +++ b/src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php @@ -0,0 +1,42 @@ + Date: Wed, 17 Mar 2021 12:39:29 +0100 Subject: [PATCH 122/187] Update change log --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86be590b..9b46323f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Fixed issue with _ spacing character in number format mask corrumpting output from toFormattedString() [Issue 1924#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1924) [PR #1927](https://github.com/PHPOffice/PhpSpreadsheet/pull/1927) +- Fixed issue with percentage formats in number format mask rendered with toFormattedString() [Issue 1929#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1929) [PR #1928](https://github.com/PHPOffice/PhpSpreadsheet/pull/1928) +- Fixed issue with _ spacing character in number format mask corrupting output from toFormattedString() [Issue 1924#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1924) [PR #1927](https://github.com/PHPOffice/PhpSpreadsheet/pull/1927) - Fix for [Issue #1887](https://github.com/PHPOffice/PhpSpreadsheet/issues/1887) - Lose Track of Selected Cells After Save - Fixed issue with Xlsx@listWorksheetInfo not returning any data - Fixed invalid arguments triggering mb_substr() error in LEFT(), MID() and RIGHT() text functions. [Issue #640](https://github.com/PHPOffice/PhpSpreadsheet/issues/640) From 4cd6c7806e77a9a63e2c3ffabc18a5137bc3f7f9 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 17 Mar 2021 18:36:13 +0100 Subject: [PATCH 123/187] Initial unit tests for Document Properties (#1932) * Initial unit tests for Document Properties * Typehinting in the document properties class --- src/PhpSpreadsheet/Document/Properties.php | 205 +++++++----------- .../Document/PropertiesTest.php | 183 ++++++++++++++++ 2 files changed, 264 insertions(+), 124 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Document/PropertiesTest.php diff --git a/src/PhpSpreadsheet/Document/Properties.php b/src/PhpSpreadsheet/Document/Properties.php index d6aff81e..951d334d 100644 --- a/src/PhpSpreadsheet/Document/Properties.php +++ b/src/PhpSpreadsheet/Document/Properties.php @@ -5,12 +5,20 @@ namespace PhpOffice\PhpSpreadsheet\Document; class Properties { /** constants */ - const PROPERTY_TYPE_BOOLEAN = 'b'; - const PROPERTY_TYPE_INTEGER = 'i'; - const PROPERTY_TYPE_FLOAT = 'f'; - const PROPERTY_TYPE_DATE = 'd'; - const PROPERTY_TYPE_STRING = 's'; - const PROPERTY_TYPE_UNKNOWN = 'u'; + public const PROPERTY_TYPE_BOOLEAN = 'b'; + public const PROPERTY_TYPE_INTEGER = 'i'; + public const PROPERTY_TYPE_FLOAT = 'f'; + public const PROPERTY_TYPE_DATE = 'd'; + public const PROPERTY_TYPE_STRING = 's'; + public const PROPERTY_TYPE_UNKNOWN = 'u'; + + private const VALID_PROPERTY_TYPE_LIST = [ + self::PROPERTY_TYPE_BOOLEAN, + self::PROPERTY_TYPE_INTEGER, + self::PROPERTY_TYPE_FLOAT, + self::PROPERTY_TYPE_DATE, + self::PROPERTY_TYPE_STRING, + ]; /** * Creator. @@ -92,7 +100,7 @@ class Properties /** * Custom Properties. * - * @var string + * @var string[] */ private $customProperties = []; @@ -109,10 +117,8 @@ class Properties /** * Get Creator. - * - * @return string */ - public function getCreator() + public function getCreator(): string { return $this->creator; } @@ -120,11 +126,9 @@ class Properties /** * Set Creator. * - * @param string $creator - * * @return $this */ - public function setCreator($creator) + public function setCreator(string $creator): self { $this->creator = $creator; @@ -133,10 +137,8 @@ class Properties /** * Get Last Modified By. - * - * @return string */ - public function getLastModifiedBy() + public function getLastModifiedBy(): string { return $this->lastModifiedBy; } @@ -144,23 +146,19 @@ class Properties /** * Set Last Modified By. * - * @param string $pValue - * * @return $this */ - public function setLastModifiedBy($pValue) + public function setLastModifiedBy(string $modifier): self { - $this->lastModifiedBy = $pValue; + $this->lastModifiedBy = $modifier; return $this; } /** * Get Created. - * - * @return int */ - public function getCreated() + public function getCreated(): int { return $this->created; } @@ -168,33 +166,31 @@ class Properties /** * Set Created. * - * @param int|string $time + * @param null|int|string $timestamp * * @return $this */ - public function setCreated($time) + public function setCreated($timestamp): self { - if ($time === null) { - $time = time(); - } elseif (is_string($time)) { - if (is_numeric($time)) { - $time = (int) $time; + if ($timestamp === null) { + $timestamp = time(); + } elseif (is_string($timestamp)) { + if (is_numeric($timestamp)) { + $timestamp = (int) $timestamp; } else { - $time = strtotime($time); + $timestamp = strtotime($timestamp); } } - $this->created = $time; + $this->created = $timestamp; return $this; } /** * Get Modified. - * - * @return int */ - public function getModified() + public function getModified(): int { return $this->modified; } @@ -202,33 +198,31 @@ class Properties /** * Set Modified. * - * @param int|string $time + * @param null|int|string $timestamp * * @return $this */ - public function setModified($time) + public function setModified($timestamp): self { - if ($time === null) { - $time = time(); - } elseif (is_string($time)) { - if (is_numeric($time)) { - $time = (int) $time; + if ($timestamp === null) { + $timestamp = time(); + } elseif (is_string($timestamp)) { + if (is_numeric($timestamp)) { + $timestamp = (int) $timestamp; } else { - $time = strtotime($time); + $timestamp = strtotime($timestamp); } } - $this->modified = $time; + $this->modified = $timestamp; return $this; } /** * Get Title. - * - * @return string */ - public function getTitle() + public function getTitle(): string { return $this->title; } @@ -236,11 +230,9 @@ class Properties /** * Set Title. * - * @param string $title - * * @return $this */ - public function setTitle($title) + public function setTitle(string $title): self { $this->title = $title; @@ -249,10 +241,8 @@ class Properties /** * Get Description. - * - * @return string */ - public function getDescription() + public function getDescription(): string { return $this->description; } @@ -260,11 +250,9 @@ class Properties /** * Set Description. * - * @param string $description - * * @return $this */ - public function setDescription($description) + public function setDescription(string $description): self { $this->description = $description; @@ -273,10 +261,8 @@ class Properties /** * Get Subject. - * - * @return string */ - public function getSubject() + public function getSubject(): string { return $this->subject; } @@ -284,11 +270,9 @@ class Properties /** * Set Subject. * - * @param string $subject - * * @return $this */ - public function setSubject($subject) + public function setSubject(string $subject): self { $this->subject = $subject; @@ -297,10 +281,8 @@ class Properties /** * Get Keywords. - * - * @return string */ - public function getKeywords() + public function getKeywords(): string { return $this->keywords; } @@ -308,11 +290,9 @@ class Properties /** * Set Keywords. * - * @param string $keywords - * * @return $this */ - public function setKeywords($keywords) + public function setKeywords(string $keywords): self { $this->keywords = $keywords; @@ -321,10 +301,8 @@ class Properties /** * Get Category. - * - * @return string */ - public function getCategory() + public function getCategory(): string { return $this->category; } @@ -332,11 +310,9 @@ class Properties /** * Set Category. * - * @param string $category - * * @return $this */ - public function setCategory($category) + public function setCategory(string $category): self { $this->category = $category; @@ -345,10 +321,8 @@ class Properties /** * Get Company. - * - * @return string */ - public function getCompany() + public function getCompany(): string { return $this->company; } @@ -356,11 +330,9 @@ class Properties /** * Set Company. * - * @param string $company - * * @return $this */ - public function setCompany($company) + public function setCompany(string $company): self { $this->company = $company; @@ -369,10 +341,8 @@ class Properties /** * Get Manager. - * - * @return string */ - public function getManager() + public function getManager(): string { return $this->manager; } @@ -380,11 +350,9 @@ class Properties /** * Set Manager. * - * @param string $manager - * * @return $this */ - public function setManager($manager) + public function setManager(string $manager): self { $this->manager = $manager; @@ -394,33 +362,27 @@ class Properties /** * Get a List of Custom Property Names. * - * @return array of string + * @return string[] */ - public function getCustomProperties() + public function getCustomProperties(): array { return array_keys($this->customProperties); } /** * Check if a Custom Property is defined. - * - * @param string $propertyName - * - * @return bool */ - public function isCustomPropertySet($propertyName) + public function isCustomPropertySet(string $propertyName): bool { - return isset($this->customProperties[$propertyName]); + return array_key_exists($propertyName, $this->customProperties); } /** * Get a Custom Property Value. * - * @param string $propertyName - * * @return mixed */ - public function getCustomPropertyValue($propertyName) + public function getCustomPropertyValue(string $propertyName) { if (isset($this->customProperties[$propertyName])) { return $this->customProperties[$propertyName]['value']; @@ -430,24 +392,36 @@ class Properties /** * Get a Custom Property Type. * - * @param string $propertyName - * * @return string */ - public function getCustomPropertyType($propertyName) + public function getCustomPropertyType(string $propertyName) { if (isset($this->customProperties[$propertyName])) { return $this->customProperties[$propertyName]['type']; } } + private function identifyPropertyType($propertyValue) + { + if ($propertyValue === null) { + return self::PROPERTY_TYPE_STRING; + } elseif (is_float($propertyValue)) { + return self::PROPERTY_TYPE_FLOAT; + } elseif (is_int($propertyValue)) { + return self::PROPERTY_TYPE_INTEGER; + } elseif (is_bool($propertyValue)) { + return self::PROPERTY_TYPE_BOOLEAN; + } + + return self::PROPERTY_TYPE_STRING; + } + /** * Set a Custom Property. * - * @param string $propertyName * @param mixed $propertyValue * @param string $propertyType - * 'i' : Integer + * 'i' : Integer * 'f' : Floating Point * 's' : String * 'd' : Date/Time @@ -455,27 +429,10 @@ class Properties * * @return $this */ - public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null) + public function setCustomProperty(string $propertyName, $propertyValue = '', $propertyType = null): self { - if ( - ($propertyType === null) || (!in_array($propertyType, [self::PROPERTY_TYPE_INTEGER, - self::PROPERTY_TYPE_FLOAT, - self::PROPERTY_TYPE_STRING, - self::PROPERTY_TYPE_DATE, - self::PROPERTY_TYPE_BOOLEAN, - ])) - ) { - if ($propertyValue === null) { - $propertyType = self::PROPERTY_TYPE_STRING; - } elseif (is_float($propertyValue)) { - $propertyType = self::PROPERTY_TYPE_FLOAT; - } elseif (is_int($propertyValue)) { - $propertyType = self::PROPERTY_TYPE_INTEGER; - } elseif (is_bool($propertyValue)) { - $propertyType = self::PROPERTY_TYPE_BOOLEAN; - } else { - $propertyType = self::PROPERTY_TYPE_STRING; - } + if (($propertyType === null) || (!in_array($propertyType, self::VALID_PROPERTY_TYPE_LIST))) { + $propertyType = $this->identifyPropertyType($propertyValue); } $this->customProperties[$propertyName] = [ @@ -501,7 +458,7 @@ class Properties } } - public static function convertProperty($propertyValue, $propertyType) + public static function convertProperty($propertyValue, string $propertyType) { switch ($propertyType) { case 'empty': // Empty @@ -552,7 +509,7 @@ class Properties return $propertyValue; } - public static function convertPropertyType($propertyType) + public static function convertPropertyType(string $propertyType): string { switch ($propertyType) { case 'i1': // 1-Byte Signed Integer diff --git a/tests/PhpSpreadsheetTests/Document/PropertiesTest.php b/tests/PhpSpreadsheetTests/Document/PropertiesTest.php new file mode 100644 index 00000000..567cf620 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Document/PropertiesTest.php @@ -0,0 +1,183 @@ +properties = new Properties(); + } + + public function testNewInstance(): void + { + $createdTime = $modifiedTime = time(); + self::assertSame('Unknown Creator', $this->properties->getCreator()); + self::assertSame('Unknown Creator', $this->properties->getLastModifiedBy()); + self::assertSame('Untitled Spreadsheet', $this->properties->getTitle()); + self::assertSame('Microsoft Corporation', $this->properties->getCompany()); + self::assertSame($createdTime, $this->properties->getCreated()); + self::assertSame($modifiedTime, $this->properties->getModified()); + } + + public function testSetCreator(): void + { + $creator = 'Mark Baker'; + + $this->properties->setCreator($creator); + self::assertSame($creator, $this->properties->getCreator()); + } + + /** + * @dataProvider providerCreationTime + * + * @param mixed $expectedCreationTime + * @param mixed $created + */ + public function testSetCreated($expectedCreationTime, $created): void + { + $expectedCreationTime = $expectedCreationTime ?? time(); + + $this->properties->setCreated($created); + self::assertSame($expectedCreationTime, $this->properties->getCreated()); + } + + public function providerCreationTime(): array + { + return [ + [null, null], + [1615980600, 1615980600], + [1615980600, '1615980600'], + [1615980600, '2021-03-17 11:30:00Z'], + ]; + } + + public function testSetModifier(): void + { + $creator = 'Mark Baker'; + + $this->properties->setLastModifiedBy($creator); + self::assertSame($creator, $this->properties->getLastModifiedBy()); + } + + /** + * @dataProvider providerModifiedTime + * + * @param mixed $expectedModifiedTime + * @param mixed $modified + */ + public function testSetModified($expectedModifiedTime, $modified): void + { + $expectedModifiedTime = $expectedModifiedTime ?? time(); + + $this->properties->setModified($modified); + self::assertSame($expectedModifiedTime, $this->properties->getModified()); + } + + public function providerModifiedTime(): array + { + return [ + [null, null], + [1615980600, 1615980600], + [1615980600, '1615980600'], + [1615980600, '2021-03-17 11:30:00Z'], + ]; + } + + public function testSetTitle(): void + { + $title = 'My spreadsheet title test'; + + $this->properties->setTitle($title); + self::assertSame($title, $this->properties->getTitle()); + } + + public function testSetDescription(): void + { + $description = 'A test for spreadsheet description'; + + $this->properties->setDescription($description); + self::assertSame($description, $this->properties->getDescription()); + } + + public function testSetSubject(): void + { + $subject = 'Test spreadsheet'; + + $this->properties->setSubject($subject); + self::assertSame($subject, $this->properties->getSubject()); + } + + public function testSetKeywords(): void + { + $keywords = 'Test PHPSpreadsheet Spreadsheet Excel LibreOffice Gnumeric OpenSpreadsheetML OASIS'; + + $this->properties->setKeywords($keywords); + self::assertSame($keywords, $this->properties->getKeywords()); + } + + public function testSetCategory(): void + { + $category = 'Testing'; + + $this->properties->setCategory($category); + self::assertSame($category, $this->properties->getCategory()); + } + + public function testSetCompany(): void + { + $company = 'PHPOffice Suite'; + + $this->properties->setCompany($company); + self::assertSame($company, $this->properties->getCompany()); + } + + public function testSetManager(): void + { + $manager = 'Mark Baker'; + + $this->properties->setManager($manager); + self::assertSame($manager, $this->properties->getManager()); + } + + /** + * @dataProvider providerCustomProperties + * + * @param mixed $expectedType + * @param mixed $expectedValue + * @param mixed $propertyName + */ + public function testSetCustomProperties($expectedType, $expectedValue, $propertyName, ...$args): void + { + $this->properties->setCustomProperty($propertyName, ...$args); + self::assertTrue($this->properties->isCustomPropertySet($propertyName)); + self::assertSame($expectedValue, $this->properties->getCustomPropertyValue($propertyName)); + self::assertSame($expectedType, $this->properties->getCustomPropertyType($propertyName)); + } + + public function providerCustomProperties(): array + { + return [ + [Properties::PROPERTY_TYPE_STRING, null, 'Editor', null], + [Properties::PROPERTY_TYPE_STRING, 'Mark Baker', 'Editor', 'Mark Baker'], + [Properties::PROPERTY_TYPE_FLOAT, 1.17, 'Version', 1.17], + [Properties::PROPERTY_TYPE_INTEGER, 2, 'Revision', 2], + [Properties::PROPERTY_TYPE_BOOLEAN, true, 'Tested', true], + [Properties::PROPERTY_TYPE_DATE, '2021-03-17', 'Test Date', '2021-03-17', Properties::PROPERTY_TYPE_DATE], + ]; + } + + public function testGetUnknownCustomProperties(): void + { + $propertyName = 'I DONT EXIST'; + + self::assertFalse($this->properties->isCustomPropertySet($propertyName)); + self::assertNull($this->properties->getCustomPropertyValue($propertyName)); + self::assertNull($this->properties->getCustomPropertyType($propertyName)); + } +} From e59c751276d91c80b63a3194ea9cbe0ea656fa20 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 17 Mar 2021 23:35:44 +0100 Subject: [PATCH 124/187] Fix reference to deprecated transpose in lookup (#1935) * Fix reference to the deprecated `TRANSPOSE()` function in `LOOKUP()`, pointing to the new `transpose()` method in the `LookupRef\Matrix` class instead --- src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php b/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php index 9d75efb0..e21d35dc 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php @@ -29,7 +29,7 @@ class Lookup $lookupColumns = self::columnCount($lookupVector); // we correctly orient our results if (($lookupRows === 1 && $lookupColumns > 1) || (!$hasResultVector && $lookupRows === 2 && $lookupColumns !== 2)) { - $lookupVector = LookupRef::TRANSPOSE($lookupVector); + $lookupVector = LookupRef\Matrix::transpose($lookupVector); $lookupRows = self::rowCount($lookupVector); $lookupColumns = self::columnCount($lookupVector); } @@ -84,7 +84,7 @@ class Lookup // we correctly orient our results if ($resultRows === 1 && $resultColumns > 1) { - $resultVector = LookupRef::TRANSPOSE($resultVector); + $resultVector = LookupRef\Matrix::transpose($resultVector); } return $resultVector; From 4e8a926cb42c636c0e60070cdce449bc88bf3ea2 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 19 Mar 2021 18:50:43 +0100 Subject: [PATCH 125/187] Final part of breaking down the Engineering class for Excel Engineering functions into smaller individual/group classes (#1940) * Final breaking down the Engineering class for Excel Engineering functions into smaller individual/group classes * Additional unhappy path tests for Complex Number functions * Fix return docblocks for floats to allow for error strings --- .../Calculation/Calculation.php | 52 +- .../Calculation/Engineering.php | 298 +++++----- .../Calculation/Engineering/Complex.php | 94 ++++ .../Engineering/ComplexFunctions.php | 513 ++++++++++++++++++ .../Engineering/ComplexOperations.php | 120 ++++ .../Calculation/Engineering/Constants.php | 11 + .../data/Calculation/Engineering/COMPLEX.php | 14 +- tests/data/Calculation/Engineering/IMABS.php | 6 + .../Calculation/Engineering/IMAGINARY.php | 6 + .../Calculation/Engineering/IMARGUMENT.php | 6 + .../Calculation/Engineering/IMCONJUGATE.php | 6 + tests/data/Calculation/Engineering/IMCOS.php | 6 + tests/data/Calculation/Engineering/IMCOSH.php | 6 + tests/data/Calculation/Engineering/IMCOT.php | 6 + tests/data/Calculation/Engineering/IMCSC.php | 6 + tests/data/Calculation/Engineering/IMCSCH.php | 6 + tests/data/Calculation/Engineering/IMDIV.php | 9 +- tests/data/Calculation/Engineering/IMEXP.php | 6 + tests/data/Calculation/Engineering/IMLN.php | 8 +- .../data/Calculation/Engineering/IMLOG10.php | 8 +- tests/data/Calculation/Engineering/IMLOG2.php | 8 +- .../data/Calculation/Engineering/IMPOWER.php | 9 +- .../Calculation/Engineering/IMPRODUCT.php | 9 +- tests/data/Calculation/Engineering/IMREAL.php | 6 + tests/data/Calculation/Engineering/IMSEC.php | 6 + tests/data/Calculation/Engineering/IMSECH.php | 6 + tests/data/Calculation/Engineering/IMSIN.php | 6 + tests/data/Calculation/Engineering/IMSINH.php | 6 + tests/data/Calculation/Engineering/IMSQRT.php | 6 + tests/data/Calculation/Engineering/IMSUB.php | 9 +- tests/data/Calculation/Engineering/IMSUM.php | 11 +- tests/data/Calculation/Engineering/IMTAN.php | 6 + 32 files changed, 1082 insertions(+), 193 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/Complex.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ComplexFunctions.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/ComplexOperations.php create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/Constants.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 5674cb72..871a0b22 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -565,7 +565,7 @@ class Calculation ], 'COMPLEX' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'COMPLEX'], + 'functionCall' => [Engineering\Complex::class, 'COMPLEX'], 'argumentCount' => '2,3', ], 'CONCAT' => [ @@ -1278,127 +1278,127 @@ class Calculation ], 'IMABS' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMABS'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMABS'], 'argumentCount' => '1', ], 'IMAGINARY' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMAGINARY'], + 'functionCall' => [Engineering\Complex::class, 'IMAGINARY'], 'argumentCount' => '1', ], 'IMARGUMENT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMARGUMENT'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMARGUMENT'], 'argumentCount' => '1', ], 'IMCONJUGATE' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMCONJUGATE'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMCONJUGATE'], 'argumentCount' => '1', ], 'IMCOS' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMCOS'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMCOS'], 'argumentCount' => '1', ], 'IMCOSH' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMCOSH'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMCOSH'], 'argumentCount' => '1', ], 'IMCOT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMCOT'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMCOT'], 'argumentCount' => '1', ], 'IMCSC' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMCSC'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMCSC'], 'argumentCount' => '1', ], 'IMCSCH' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMCSCH'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMCSCH'], 'argumentCount' => '1', ], 'IMDIV' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMDIV'], + 'functionCall' => [Engineering\ComplexOperations::class, 'IMDIV'], 'argumentCount' => '2', ], 'IMEXP' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMEXP'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMEXP'], 'argumentCount' => '1', ], 'IMLN' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMLN'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMLN'], 'argumentCount' => '1', ], 'IMLOG10' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMLOG10'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMLOG10'], 'argumentCount' => '1', ], 'IMLOG2' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMLOG2'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMLOG2'], 'argumentCount' => '1', ], 'IMPOWER' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMPOWER'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMPOWER'], 'argumentCount' => '2', ], 'IMPRODUCT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMPRODUCT'], + 'functionCall' => [Engineering\ComplexOperations::class, 'IMPRODUCT'], 'argumentCount' => '1+', ], 'IMREAL' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMREAL'], + 'functionCall' => [Engineering\Complex::class, 'IMREAL'], 'argumentCount' => '1', ], 'IMSEC' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSEC'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMSEC'], 'argumentCount' => '1', ], 'IMSECH' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSECH'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMSECH'], 'argumentCount' => '1', ], 'IMSIN' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSIN'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMSIN'], 'argumentCount' => '1', ], 'IMSINH' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSINH'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMSINH'], 'argumentCount' => '1', ], 'IMSQRT' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSQRT'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMSQRT'], 'argumentCount' => '1', ], 'IMSUB' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSUB'], + 'functionCall' => [Engineering\ComplexOperations::class, 'IMSUB'], 'argumentCount' => '2', ], 'IMSUM' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMSUM'], + 'functionCall' => [Engineering\ComplexOperations::class, 'IMSUM'], 'argumentCount' => '1+', ], 'IMTAN' => [ 'category' => Category::CATEGORY_ENGINEERING, - 'functionCall' => [Engineering::class, 'IMTAN'], + 'functionCall' => [Engineering\ComplexFunctions::class, 'IMTAN'], 'argumentCount' => '1', ], 'INDEX' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index f311fe99..229607e2 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -3,14 +3,21 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use Complex\Complex; -use Complex\Exception as ComplexException; +use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ComplexFunctions; +use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ComplexOperations; +/** + * @deprecated 1.18.0 + */ class Engineering { /** * EULER. + * + * @deprecated 1.18.0 + * @see Use Engineering\Constants\EULER instead */ - const EULER = 2.71828182845904523536; + public const EULER = 2.71828182845904523536; /** * parseComplex. @@ -552,6 +559,10 @@ class Engineering * Excel Function: * COMPLEX(realNumber,imaginary[,suffix]) * + * @Deprecated 1.18.0 + * + * @see Use the COMPLEX() method in the Engineering\Complex class instead + * * @param float $realNumber the real coefficient of the complex number * @param float $imaginary the imaginary coefficient of the complex number * @param string $suffix The suffix for the imaginary component of the complex number. @@ -561,20 +572,7 @@ class Engineering */ public static function COMPLEX($realNumber = 0.0, $imaginary = 0.0, $suffix = 'i') { - $realNumber = ($realNumber === null) ? 0.0 : Functions::flattenSingleValue($realNumber); - $imaginary = ($imaginary === null) ? 0.0 : Functions::flattenSingleValue($imaginary); - $suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix); - - if ( - ((is_numeric($realNumber)) && (is_numeric($imaginary))) && - (($suffix == 'i') || ($suffix == 'j') || ($suffix == '')) - ) { - $complex = new Complex($realNumber, $imaginary, $suffix); - - return (string) $complex; - } - - return Functions::VALUE(); + return Engineering\Complex::COMPLEX($realNumber, $imaginary, $suffix); } /** @@ -585,16 +583,18 @@ class Engineering * Excel Function: * IMAGINARY(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMAGINARY() method in the Engineering\Complex class instead + * * @param string $complexNumber the complex number for which you want the imaginary * coefficient * - * @return float + * @return float|string */ public static function IMAGINARY($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (new Complex($complexNumber))->getImaginary(); + return Engineering\Complex::IMAGINARY($complexNumber); } /** @@ -605,15 +605,17 @@ class Engineering * Excel Function: * IMREAL(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMREAL() method in the Engineering\Complex class instead + * * @param string $complexNumber the complex number for which you want the real coefficient * - * @return float + * @return float|string */ public static function IMREAL($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (new Complex($complexNumber))->getReal(); + return Engineering\Complex::IMREAL($complexNumber); } /** @@ -624,15 +626,17 @@ class Engineering * Excel Function: * IMABS(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMABS() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the absolute value * - * @return float + * @return float|string */ public static function IMABS($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (new Complex($complexNumber))->abs(); + return ComplexFunctions::IMABS($complexNumber); } /** @@ -644,20 +648,17 @@ class Engineering * Excel Function: * IMARGUMENT(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMARGUMENT() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the argument theta * * @return float|string */ public static function IMARGUMENT($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - $complex = new Complex($complexNumber); - if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { - return Functions::DIV0(); - } - - return $complex->argument(); + return ComplexFunctions::IMARGUMENT($complexNumber); } /** @@ -668,15 +669,17 @@ class Engineering * Excel Function: * IMCONJUGATE(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMARGUMENT() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the conjugate * * @return string */ public static function IMCONJUGATE($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->conjugate(); + return ComplexFunctions::IMCONJUGATE($complexNumber); } /** @@ -687,15 +690,17 @@ class Engineering * Excel Function: * IMCOS(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMCOS() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the cosine * * @return float|string */ public static function IMCOS($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->cos(); + return ComplexFunctions::IMCOS($complexNumber); } /** @@ -706,15 +711,17 @@ class Engineering * Excel Function: * IMCOSH(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMCOSH() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the hyperbolic cosine * * @return float|string */ public static function IMCOSH($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->cosh(); + return ComplexFunctions::IMCOSH($complexNumber); } /** @@ -725,15 +732,17 @@ class Engineering * Excel Function: * IMCOT(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMCOT() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the cotangent * * @return float|string */ public static function IMCOT($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->cot(); + return ComplexFunctions::IMCOT($complexNumber); } /** @@ -744,15 +753,17 @@ class Engineering * Excel Function: * IMCSC(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMCSC() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the cosecant * * @return float|string */ public static function IMCSC($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->csc(); + return ComplexFunctions::IMCSC($complexNumber); } /** @@ -763,15 +774,17 @@ class Engineering * Excel Function: * IMCSCH(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMCSCH() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the hyperbolic cosecant * * @return float|string */ public static function IMCSCH($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->csch(); + return ComplexFunctions::IMCSCH($complexNumber); } /** @@ -782,15 +795,17 @@ class Engineering * Excel Function: * IMSIN(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMSIN() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the sine * * @return float|string */ public static function IMSIN($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->sin(); + return ComplexFunctions::IMSIN($complexNumber); } /** @@ -801,15 +816,17 @@ class Engineering * Excel Function: * IMSINH(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMSINH() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the hyperbolic sine * * @return float|string */ public static function IMSINH($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->sinh(); + return ComplexFunctions::IMSINH($complexNumber); } /** @@ -820,15 +837,17 @@ class Engineering * Excel Function: * IMSEC(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMSEC() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the secant * * @return float|string */ public static function IMSEC($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->sec(); + return ComplexFunctions::IMSEC($complexNumber); } /** @@ -839,15 +858,17 @@ class Engineering * Excel Function: * IMSECH(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMSECH() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the hyperbolic secant * * @return float|string */ public static function IMSECH($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->sech(); + return ComplexFunctions::IMSECH($complexNumber); } /** @@ -858,15 +879,17 @@ class Engineering * Excel Function: * IMTAN(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMTAN() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the tangent * * @return float|string */ public static function IMTAN($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->tan(); + return ComplexFunctions::IMTAN($complexNumber); } /** @@ -877,20 +900,17 @@ class Engineering * Excel Function: * IMSQRT(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMSQRT() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the square root * * @return string */ public static function IMSQRT($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - $theta = self::IMARGUMENT($complexNumber); - if ($theta === Functions::DIV0()) { - return '0'; - } - - return (string) (new Complex($complexNumber))->sqrt(); + return ComplexFunctions::IMSQRT($complexNumber); } /** @@ -901,20 +921,17 @@ class Engineering * Excel Function: * IMLN(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMLN() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the natural logarithm * * @return string */ public static function IMLN($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - $complex = new Complex($complexNumber); - if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { - return Functions::NAN(); - } - - return (string) (new Complex($complexNumber))->ln(); + return ComplexFunctions::IMLN($complexNumber); } /** @@ -925,20 +942,17 @@ class Engineering * Excel Function: * IMLOG10(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMLOG10() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the common logarithm * * @return string */ public static function IMLOG10($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - $complex = new Complex($complexNumber); - if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { - return Functions::NAN(); - } - - return (string) (new Complex($complexNumber))->log10(); + return ComplexFunctions::IMLOG10($complexNumber); } /** @@ -949,20 +963,17 @@ class Engineering * Excel Function: * IMLOG2(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMLOG2() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the base-2 logarithm * * @return string */ public static function IMLOG2($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - $complex = new Complex($complexNumber); - if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { - return Functions::NAN(); - } - - return (string) (new Complex($complexNumber))->log2(); + return ComplexFunctions::IMLOG2($complexNumber); } /** @@ -973,15 +984,17 @@ class Engineering * Excel Function: * IMEXP(complexNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMEXP() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number for which you want the exponential * * @return string */ public static function IMEXP($complexNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - - return (string) (new Complex($complexNumber))->exp(); + return ComplexFunctions::IMEXP($complexNumber); } /** @@ -992,6 +1005,10 @@ class Engineering * Excel Function: * IMPOWER(complexNumber,realNumber) * + * @Deprecated 1.18.0 + * + * @see Use the IMPOWER() method in the Engineering\ComplexFunctions class instead + * * @param string $complexNumber the complex number you want to raise to a power * @param float $realNumber the power to which you want to raise the complex number * @@ -999,14 +1016,7 @@ class Engineering */ public static function IMPOWER($complexNumber, $realNumber) { - $complexNumber = Functions::flattenSingleValue($complexNumber); - $realNumber = Functions::flattenSingleValue($realNumber); - - if (!is_numeric($realNumber)) { - return Functions::VALUE(); - } - - return (string) (new Complex($complexNumber))->pow($realNumber); + return ComplexFunctions::IMPOWER($complexNumber, $realNumber); } /** @@ -1017,6 +1027,10 @@ class Engineering * Excel Function: * IMDIV(complexDividend,complexDivisor) * + * @Deprecated 1.18.0 + * + * @see Use the IMDIV() method in the Engineering\ComplexOperations class instead + * * @param string $complexDividend the complex numerator or dividend * @param string $complexDivisor the complex denominator or divisor * @@ -1024,14 +1038,7 @@ class Engineering */ public static function IMDIV($complexDividend, $complexDivisor) { - $complexDividend = Functions::flattenSingleValue($complexDividend); - $complexDivisor = Functions::flattenSingleValue($complexDivisor); - - try { - return (string) (new Complex($complexDividend))->divideby(new Complex($complexDivisor)); - } catch (ComplexException $e) { - return Functions::NAN(); - } + return ComplexOperations::IMDIV($complexDividend, $complexDivisor); } /** @@ -1042,6 +1049,10 @@ class Engineering * Excel Function: * IMSUB(complexNumber1,complexNumber2) * + * @Deprecated 1.18.0 + * + * @see Use the IMSUB() method in the Engineering\ComplexOperations class instead + * * @param string $complexNumber1 the complex number from which to subtract complexNumber2 * @param string $complexNumber2 the complex number to subtract from complexNumber1 * @@ -1049,14 +1060,7 @@ class Engineering */ public static function IMSUB($complexNumber1, $complexNumber2) { - $complexNumber1 = Functions::flattenSingleValue($complexNumber1); - $complexNumber2 = Functions::flattenSingleValue($complexNumber2); - - try { - return (string) (new Complex($complexNumber1))->subtract(new Complex($complexNumber2)); - } catch (ComplexException $e) { - return Functions::NAN(); - } + return ComplexOperations::IMSUB($complexNumber1, $complexNumber2); } /** @@ -1067,26 +1071,17 @@ class Engineering * Excel Function: * IMSUM(complexNumber[,complexNumber[,...]]) * + * @Deprecated 1.18.0 + * + * @see Use the IMSUM() method in the Engineering\ComplexOperations class instead + * * @param string ...$complexNumbers Series of complex numbers to add * * @return string */ public static function IMSUM(...$complexNumbers) { - // Return value - $returnValue = new Complex(0.0); - $aArgs = Functions::flattenArray($complexNumbers); - - try { - // Loop through the arguments - foreach ($aArgs as $complex) { - $returnValue = $returnValue->add(new Complex($complex)); - } - } catch (ComplexException $e) { - return Functions::NAN(); - } - - return (string) $returnValue; + return ComplexOperations::IMSUM(...$complexNumbers); } /** @@ -1097,26 +1092,17 @@ class Engineering * Excel Function: * IMPRODUCT(complexNumber[,complexNumber[,...]]) * + * @Deprecated 1.18.0 + * + * @see Use the IMPRODUCT() method in the Engineering\ComplexOperations class instead + * * @param string ...$complexNumbers Series of complex numbers to multiply * * @return string */ public static function IMPRODUCT(...$complexNumbers) { - // Return value - $returnValue = new Complex(1.0); - $aArgs = Functions::flattenArray($complexNumbers); - - try { - // Loop through the arguments - foreach ($aArgs as $complex) { - $returnValue = $returnValue->multiply(new Complex($complex)); - } - } catch (ComplexException $e) { - return Functions::NAN(); - } - - return (string) $returnValue; + return ComplexOperations::IMPRODUCT(...$complexNumbers); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php new file mode 100644 index 00000000..f6429cbd --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php @@ -0,0 +1,94 @@ +getImaginary(); + } + + /** + * IMREAL. + * + * Returns the real coefficient of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMREAL(complexNumber) + * + * @param string $complexNumber the complex number for which you want the real coefficient + * + * @return float|string + */ + public static function IMREAL($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return $complex->getReal(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ComplexFunctions.php b/src/PhpSpreadsheet/Calculation/Engineering/ComplexFunctions.php new file mode 100644 index 00000000..3f37f373 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ComplexFunctions.php @@ -0,0 +1,513 @@ +abs(); + } + + /** + * IMARGUMENT. + * + * Returns the argument theta of a complex number, i.e. the angle in radians from the real + * axis to the representation of the number in polar coordinates. + * + * Excel Function: + * IMARGUMENT(complexNumber) + * + * @param string $complexNumber the complex number for which you want the argument theta + * + * @return float|string + */ + public static function IMARGUMENT($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return Functions::DIV0(); + } + + return $complex->argument(); + } + + /** + * IMCONJUGATE. + * + * Returns the complex conjugate of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMCONJUGATE(complexNumber) + * + * @param string $complexNumber the complex number for which you want the conjugate + * + * @return string + */ + public static function IMCONJUGATE($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->conjugate(); + } + + /** + * IMCOS. + * + * Returns the cosine of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMCOS(complexNumber) + * + * @param string $complexNumber the complex number for which you want the cosine + * + * @return float|string + */ + public static function IMCOS($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->cos(); + } + + /** + * IMCOSH. + * + * Returns the hyperbolic cosine of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMCOSH(complexNumber) + * + * @param string $complexNumber the complex number for which you want the hyperbolic cosine + * + * @return float|string + */ + public static function IMCOSH($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->cosh(); + } + + /** + * IMCOT. + * + * Returns the cotangent of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMCOT(complexNumber) + * + * @param string $complexNumber the complex number for which you want the cotangent + * + * @return float|string + */ + public static function IMCOT($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->cot(); + } + + /** + * IMCSC. + * + * Returns the cosecant of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMCSC(complexNumber) + * + * @param string $complexNumber the complex number for which you want the cosecant + * + * @return float|string + */ + public static function IMCSC($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->csc(); + } + + /** + * IMCSCH. + * + * Returns the hyperbolic cosecant of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMCSCH(complexNumber) + * + * @param string $complexNumber the complex number for which you want the hyperbolic cosecant + * + * @return float|string + */ + public static function IMCSCH($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->csch(); + } + + /** + * IMSIN. + * + * Returns the sine of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMSIN(complexNumber) + * + * @param string $complexNumber the complex number for which you want the sine + * + * @return float|string + */ + public static function IMSIN($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->sin(); + } + + /** + * IMSINH. + * + * Returns the hyperbolic sine of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMSINH(complexNumber) + * + * @param string $complexNumber the complex number for which you want the hyperbolic sine + * + * @return float|string + */ + public static function IMSINH($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->sinh(); + } + + /** + * IMSEC. + * + * Returns the secant of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMSEC(complexNumber) + * + * @param string $complexNumber the complex number for which you want the secant + * + * @return float|string + */ + public static function IMSEC($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->sec(); + } + + /** + * IMSECH. + * + * Returns the hyperbolic secant of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMSECH(complexNumber) + * + * @param string $complexNumber the complex number for which you want the hyperbolic secant + * + * @return float|string + */ + public static function IMSECH($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->sech(); + } + + /** + * IMTAN. + * + * Returns the tangent of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMTAN(complexNumber) + * + * @param string $complexNumber the complex number for which you want the tangent + * + * @return float|string + */ + public static function IMTAN($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->tan(); + } + + /** + * IMSQRT. + * + * Returns the square root of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMSQRT(complexNumber) + * + * @param string $complexNumber the complex number for which you want the square root + * + * @return string + */ + public static function IMSQRT($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + $theta = self::IMARGUMENT($complexNumber); + if ($theta === Functions::DIV0()) { + return '0'; + } + + return (string) $complex->sqrt(); + } + + /** + * IMLN. + * + * Returns the natural logarithm of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMLN(complexNumber) + * + * @param string $complexNumber the complex number for which you want the natural logarithm + * + * @return string + */ + public static function IMLN($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return Functions::NAN(); + } + + return (string) $complex->ln(); + } + + /** + * IMLOG10. + * + * Returns the common logarithm (base 10) of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMLOG10(complexNumber) + * + * @param string $complexNumber the complex number for which you want the common logarithm + * + * @return string + */ + public static function IMLOG10($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return Functions::NAN(); + } + + return (string) $complex->log10(); + } + + /** + * IMLOG2. + * + * Returns the base-2 logarithm of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMLOG2(complexNumber) + * + * @param string $complexNumber the complex number for which you want the base-2 logarithm + * + * @return string + */ + public static function IMLOG2($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) { + return Functions::NAN(); + } + + return (string) $complex->log2(); + } + + /** + * IMEXP. + * + * Returns the exponential of a complex number in x + yi or x + yj text format. + * + * Excel Function: + * IMEXP(complexNumber) + * + * @param string $complexNumber the complex number for which you want the exponential + * + * @return string + */ + public static function IMEXP($complexNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $complex->exp(); + } + + /** + * IMPOWER. + * + * Returns a complex number in x + yi or x + yj text format raised to a power. + * + * Excel Function: + * IMPOWER(complexNumber,realNumber) + * + * @param string $complexNumber the complex number you want to raise to a power + * @param float $realNumber the power to which you want to raise the complex number + * + * @return string + */ + public static function IMPOWER($complexNumber, $realNumber) + { + $complexNumber = Functions::flattenSingleValue($complexNumber); + $realNumber = Functions::flattenSingleValue($realNumber); + + try { + $complex = new ComplexObject($complexNumber); + } catch (ComplexException $e) { + return Functions::NAN(); + } + + if (!is_numeric($realNumber)) { + return Functions::VALUE(); + } + + return (string) $complex->pow($realNumber); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ComplexOperations.php b/src/PhpSpreadsheet/Calculation/Engineering/ComplexOperations.php new file mode 100644 index 00000000..681aad8c --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/ComplexOperations.php @@ -0,0 +1,120 @@ +divideby(new ComplexObject($complexDivisor)); + } catch (ComplexException $e) { + return Functions::NAN(); + } + } + + /** + * IMSUB. + * + * Returns the difference of two complex numbers in x + yi or x + yj text format. + * + * Excel Function: + * IMSUB(complexNumber1,complexNumber2) + * + * @param string $complexNumber1 the complex number from which to subtract complexNumber2 + * @param string $complexNumber2 the complex number to subtract from complexNumber1 + * + * @return string + */ + public static function IMSUB($complexNumber1, $complexNumber2) + { + $complexNumber1 = Functions::flattenSingleValue($complexNumber1); + $complexNumber2 = Functions::flattenSingleValue($complexNumber2); + + try { + return (string) (new ComplexObject($complexNumber1))->subtract(new ComplexObject($complexNumber2)); + } catch (ComplexException $e) { + return Functions::NAN(); + } + } + + /** + * IMSUM. + * + * Returns the sum of two or more complex numbers in x + yi or x + yj text format. + * + * Excel Function: + * IMSUM(complexNumber[,complexNumber[,...]]) + * + * @param string ...$complexNumbers Series of complex numbers to add + * + * @return string + */ + public static function IMSUM(...$complexNumbers) + { + // Return value + $returnValue = new ComplexObject(0.0); + $aArgs = Functions::flattenArray($complexNumbers); + + try { + // Loop through the arguments + foreach ($aArgs as $complex) { + $returnValue = $returnValue->add(new ComplexObject($complex)); + } + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $returnValue; + } + + /** + * IMPRODUCT. + * + * Returns the product of two or more complex numbers in x + yi or x + yj text format. + * + * Excel Function: + * IMPRODUCT(complexNumber[,complexNumber[,...]]) + * + * @param string ...$complexNumbers Series of complex numbers to multiply + * + * @return string + */ + public static function IMPRODUCT(...$complexNumbers) + { + // Return value + $returnValue = new ComplexObject(1.0); + $aArgs = Functions::flattenArray($complexNumbers); + + try { + // Loop through the arguments + foreach ($aArgs as $complex) { + $returnValue = $returnValue->multiply(new ComplexObject($complex)); + } + } catch (ComplexException $e) { + return Functions::NAN(); + } + + return (string) $returnValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Constants.php b/src/PhpSpreadsheet/Calculation/Engineering/Constants.php new file mode 100644 index 00000000..a926db6e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/Constants.php @@ -0,0 +1,11 @@ + Date: Sat, 20 Mar 2021 18:40:53 +0100 Subject: [PATCH 126/187] Start work on breaking down some of the Financial Excel functions (#1941) * Start work on breaking down some of the Financial Excel functions * Unhappy path unit tests for Treasury Bill functions * Codebase for Treasury Bills includes logic for a different days between settlement and maturity calculation for OpenOffice; but Open/Libre Office now uses the Excel days calculation, so this discrepancy between packages is no longer required * We've already converted the Settlement and Maturity dates to Excel timestamps, so there's no need to try doing it again when calculating the days between Settlement and Maturity * Add Unit Tests for the Days per Year helper function * Extract Interest Rate functions - EFFECT() and NOMINAL() - with additional validation, and unhappy path unit tests * First pass at extracting the Coupon Excel functions * Simplify the validation methods * Extended unit tests to cover all combinations of frequency and basis, including leap years Fix for COUPDAYSNC() when basis is US 360 and settlement date is the last day of the month * Ensure that all Financial function code uses the new Helpers class for Days Per Year --- .../Calculation/Calculation.php | 26 +- src/PhpSpreadsheet/Calculation/Financial.php | 469 ++++-------------- .../Calculation/Financial/Coupons.php | 435 ++++++++++++++++ .../Calculation/Financial/Dollar.php | 80 +++ .../Calculation/Financial/Helpers.php | 50 ++ .../Calculation/Financial/InterestRate.php | 69 +++ .../Calculation/Financial/TreasuryBill.php | 154 ++++++ .../Functions/Financial/EffectTest.php | 6 +- .../Functions/Financial/HelpersTest.php | 27 + .../Functions/Financial/NominalTest.php | 6 +- .../data/Calculation/Financial/COUPDAYBS.php | 163 +++++- tests/data/Calculation/Financial/COUPDAYS.php | 156 +++++- .../data/Calculation/Financial/COUPDAYSNC.php | 177 ++++++- tests/data/Calculation/Financial/COUPNCD.php | 151 +++++- tests/data/Calculation/Financial/COUPNUM.php | 156 +++++- tests/data/Calculation/Financial/COUPPCD.php | 151 +++++- .../Calculation/Financial/DaysPerYear.php | 15 + tests/data/Calculation/Financial/EFFECT.php | 21 +- tests/data/Calculation/Financial/NOMINAL.php | 21 +- tests/data/Calculation/Financial/TBILLEQ.php | 32 +- .../data/Calculation/Financial/TBILLPRICE.php | 36 +- .../data/Calculation/Financial/TBILLYIELD.php | 26 + 22 files changed, 2009 insertions(+), 418 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Coupons.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Dollar.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Helpers.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/InterestRate.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php create mode 100644 tests/data/Calculation/Financial/DaysPerYear.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 871a0b22..05fe8a81 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -650,32 +650,32 @@ class Calculation ], 'COUPDAYBS' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'COUPDAYBS'], + 'functionCall' => [Financial\Coupons::class, 'COUPDAYBS'], 'argumentCount' => '3,4', ], 'COUPDAYS' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'COUPDAYS'], + 'functionCall' => [Financial\Coupons::class, 'COUPDAYS'], 'argumentCount' => '3,4', ], 'COUPDAYSNC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'COUPDAYSNC'], + 'functionCall' => [Financial\Coupons::class, 'COUPDAYSNC'], 'argumentCount' => '3,4', ], 'COUPNCD' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'COUPNCD'], + 'functionCall' => [Financial\Coupons::class, 'COUPNCD'], 'argumentCount' => '3,4', ], 'COUPNUM' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'COUPNUM'], + 'functionCall' => [Financial\Coupons::class, 'COUPNUM'], 'argumentCount' => '3,4', ], 'COUPPCD' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'COUPPCD'], + 'functionCall' => [Financial\Coupons::class, 'COUPPCD'], 'argumentCount' => '3,4', ], 'COVAR' => [ @@ -875,12 +875,12 @@ class Calculation ], 'DOLLARDE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'DOLLARDE'], + 'functionCall' => [Financial\Dollar::class, 'decimal'], 'argumentCount' => '2', ], 'DOLLARFR' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'DOLLARFR'], + 'functionCall' => [Financial\Dollar::class, 'fractional'], 'argumentCount' => '2', ], 'DPRODUCT' => [ @@ -925,7 +925,7 @@ class Calculation ], 'EFFECT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'EFFECT'], + 'functionCall' => [Financial\InterestRate::class, 'effective'], 'argumentCount' => '2', ], 'ENCODEURL' => [ @@ -1771,7 +1771,7 @@ class Calculation ], 'NOMINAL' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'NOMINAL'], + 'functionCall' => [Financial\InterestRate::class, 'nominal'], 'argumentCount' => '2', ], 'NORMDIST' => [ @@ -2376,17 +2376,17 @@ class Calculation ], 'TBILLEQ' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'TBILLEQ'], + 'functionCall' => [Financial\TreasuryBill::class, 'bondEquivalentYield'], 'argumentCount' => '3', ], 'TBILLPRICE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'TBILLPRICE'], + 'functionCall' => [Financial\TreasuryBill::class, 'price'], 'argumentCount' => '3', ], 'TBILLYIELD' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'TBILLYIELD'], + 'functionCall' => [Financial\TreasuryBill::class, 'yield'], 'argumentCount' => '3', ], 'TDIST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index f0b5ab05..f6f5c775 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -2,7 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; -use PhpOffice\PhpSpreadsheet\Shared\Date; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Coupons; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\InterestRate; class Financial { @@ -10,41 +11,6 @@ class Financial const FINANCIAL_PRECISION = 1.0e-08; - /** - * isLastDayOfMonth. - * - * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month - * - * @param \DateTime $testDate The date for testing - * - * @return bool - */ - private static function isLastDayOfMonth(\DateTime $testDate) - { - return $testDate->format('d') == $testDate->format('t'); - } - - private static function couponFirstPeriodDate($settlement, $maturity, $frequency, $next) - { - $months = 12 / $frequency; - - $result = Date::excelToDateTimeObject($maturity); - $eom = self::isLastDayOfMonth($result); - - while ($settlement < Date::PHPToExcel($result)) { - $result->modify('-' . $months . ' months'); - } - if ($next) { - $result->modify('+' . $months . ' months'); - } - - if ($eom) { - $result->modify('-1 day'); - } - - return Date::PHPToExcel($result); - } - private static function isValidFrequency($frequency) { if (($frequency == 1) || ($frequency == 2) || ($frequency == 4)) { @@ -54,45 +20,6 @@ class Financial return false; } - /** - * daysPerYear. - * - * Returns the number of days in a specified year, as defined by the "basis" value - * - * @param int|string $year The year against which we're testing - * @param int|string $basis The type of day count: - * 0 or omitted US (NASD) 360 - * 1 Actual (365 or 366 in a leap year) - * 2 360 - * 3 365 - * 4 European 360 - * - * @return int|string Result, or a string containing an error - */ - private static function daysPerYear($year, $basis = 0) - { - switch ($basis) { - case 0: - case 2: - case 4: - $daysPerYear = 360; - - break; - case 3: - $daysPerYear = 365; - - break; - case 1: - $daysPerYear = (DateTime::isLeapYear($year)) ? 366 : 365; - - break; - default: - return Functions::NAN(); - } - - return $daysPerYear; - } - private static function interestAndPrincipal($rate = 0, $per = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) { $pmt = self::PMT($rate, $nper, $pv, $fv, $type); @@ -369,6 +296,10 @@ class Financial * Excel Function: * COUPDAYBS(settlement,maturity,frequency[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the COUPDAYBS() method in the Financial\Coupons class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -390,34 +321,7 @@ class Financial */ public static function COUPDAYBS($settlement, $maturity, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $frequency = (int) Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - if (is_string($settlement = DateTime::getDateValue($settlement))) { - return Functions::VALUE(); - } - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if ( - ($settlement >= $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis); - $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, false); - - if ($basis == 1) { - return abs(DateTime::DAYS($prev, $settlement)); - } - - return DateTime::YEARFRAC($prev, $settlement, $basis) * $daysPerYear; + return Coupons::COUPDAYBS($settlement, $maturity, $frequency, $basis); } /** @@ -428,6 +332,10 @@ class Financial * Excel Function: * COUPDAYS(settlement,maturity,frequency[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the COUPDAYS() method in the Financial\Coupons class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -449,45 +357,7 @@ class Financial */ public static function COUPDAYS($settlement, $maturity, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $frequency = (int) Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - if (is_string($settlement = DateTime::getDateValue($settlement))) { - return Functions::VALUE(); - } - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if ( - ($settlement >= $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - switch ($basis) { - case 3: - // Actual/365 - return 365 / $frequency; - case 1: - // Actual/actual - if ($frequency == 1) { - $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis); - - return $daysPerYear / $frequency; - } - $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, false); - $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true); - - return $next - $prev; - default: - // US (NASD) 30/360, Actual/360 or European 30/360 - return 360 / $frequency; - } + return Coupons::COUPDAYS($settlement, $maturity, $frequency, $basis); } /** @@ -498,6 +368,10 @@ class Financial * Excel Function: * COUPDAYSNC(settlement,maturity,frequency[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the COUPDAYSNC() method in the Financial\Coupons class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -519,30 +393,7 @@ class Financial */ public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $frequency = (int) Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - if (is_string($settlement = DateTime::getDateValue($settlement))) { - return Functions::VALUE(); - } - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if ( - ($settlement >= $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis); - $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true); - - return DateTime::YEARFRAC($settlement, $next, $basis) * $daysPerYear; + return Coupons::COUPDAYSNC($settlement, $maturity, $frequency, $basis); } /** @@ -553,6 +404,10 @@ class Financial * Excel Function: * COUPNCD(settlement,maturity,frequency[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the COUPNCD() method in the Financial\Coupons class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -575,27 +430,7 @@ class Financial */ public static function COUPNCD($settlement, $maturity, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $frequency = (int) Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - if (is_string($settlement = DateTime::getDateValue($settlement))) { - return Functions::VALUE(); - } - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if ( - ($settlement >= $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - return self::couponFirstPeriodDate($settlement, $maturity, $frequency, true); + return Coupons::COUPNCD($settlement, $maturity, $frequency, $basis); } /** @@ -607,6 +442,10 @@ class Financial * Excel Function: * COUPNUM(settlement,maturity,frequency[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the COUPNUM() method in the Financial\Coupons class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -628,29 +467,7 @@ class Financial */ public static function COUPNUM($settlement, $maturity, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $frequency = (int) Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - if (is_string($settlement = DateTime::getDateValue($settlement))) { - return Functions::VALUE(); - } - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if ( - ($settlement >= $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - $yearsBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, 0); - - return ceil($yearsBetweenSettlementAndMaturity * $frequency); + return Coupons::COUPNUM($settlement, $maturity, $frequency, $basis); } /** @@ -661,6 +478,10 @@ class Financial * Excel Function: * COUPPCD(settlement,maturity,frequency[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the COUPPCD() method in the Financial\Coupons class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -683,27 +504,7 @@ class Financial */ public static function COUPPCD($settlement, $maturity, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $frequency = (int) Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - if (is_string($settlement = DateTime::getDateValue($settlement))) { - return Functions::VALUE(); - } - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if ( - ($settlement >= $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - return self::couponFirstPeriodDate($settlement, $maturity, $frequency, false); + return Coupons::COUPPCD($settlement, $maturity, $frequency, $basis); } /** @@ -997,6 +798,10 @@ class Financial * Excel Function: * DOLLARDE(fractional_dollar,fraction) * + * @Deprecated 1.18.0 + * + * @see Use the decimal() method in the Financial\Dollar class instead + * * @param float $fractional_dollar Fractional Dollar * @param int $fraction Fraction * @@ -1004,23 +809,7 @@ class Financial */ public static function DOLLARDE($fractional_dollar = null, $fraction = 0) { - $fractional_dollar = Functions::flattenSingleValue($fractional_dollar); - $fraction = (int) Functions::flattenSingleValue($fraction); - - // Validate parameters - if ($fractional_dollar === null || $fraction < 0) { - return Functions::NAN(); - } - if ($fraction == 0) { - return Functions::DIV0(); - } - - $dollars = floor($fractional_dollar); - $cents = fmod($fractional_dollar, 1); - $cents /= $fraction; - $cents *= 10 ** ceil(log10($fraction)); - - return $dollars + $cents; + return Financial\Dollar::decimal($fractional_dollar, $fraction); } /** @@ -1033,6 +822,10 @@ class Financial * Excel Function: * DOLLARFR(decimal_dollar,fraction) * + * @Deprecated 1.18.0 + * + * @see Use the fractional() method in the Financial\Dollar class instead + * * @param float $decimal_dollar Decimal Dollar * @param int $fraction Fraction * @@ -1040,23 +833,7 @@ class Financial */ public static function DOLLARFR($decimal_dollar = null, $fraction = 0) { - $decimal_dollar = Functions::flattenSingleValue($decimal_dollar); - $fraction = (int) Functions::flattenSingleValue($fraction); - - // Validate parameters - if ($decimal_dollar === null || $fraction < 0) { - return Functions::NAN(); - } - if ($fraction == 0) { - return Functions::DIV0(); - } - - $dollars = floor($decimal_dollar); - $cents = fmod($decimal_dollar, 1); - $cents *= $fraction; - $cents *= 10 ** (-ceil(log10($fraction))); - - return $dollars + $cents; + return Financial\Dollar::fractional($decimal_dollar, $fraction); } /** @@ -1068,22 +845,18 @@ class Financial * Excel Function: * EFFECT(nominal_rate,npery) * - * @param float $nominal_rate Nominal interest rate - * @param int $npery Number of compounding payments per year + * @Deprecated 1.18.0 + * + * @see Use the effective() method in the Financial\InterestRate class instead + * + * @param float $nominalRate Nominal interest rate + * @param int $periodsPerYear Number of compounding payments per year * * @return float|string */ - public static function EFFECT($nominal_rate = 0, $npery = 0) + public static function EFFECT($nominalRate = 0, $periodsPerYear = 0) { - $nominal_rate = Functions::flattenSingleValue($nominal_rate); - $npery = (int) Functions::flattenSingleValue($npery); - - // Validate parameters - if ($nominal_rate <= 0 || $npery < 1) { - return Functions::NAN(); - } - - return (1 + $nominal_rate / $npery) ** $npery - 1; + return Financial\InterestRate::effective($nominalRate, $periodsPerYear); } /** @@ -1412,23 +1185,21 @@ class Financial * * Returns the nominal interest rate given the effective rate and the number of compounding payments per year. * - * @param float $effect_rate Effective interest rate - * @param int $npery Number of compounding payments per year + * Excel Function: + * NOMINAL(effect_rate, npery) + * + * @Deprecated 1.18.0 + * + * @see Use the nominal() method in the Financial\InterestRate class instead + * + * @param float $effectiveRate Effective interest rate + * @param int $periodsPerYear Number of compounding payments per year * * @return float|string Result, or a string containing an error */ - public static function NOMINAL($effect_rate = 0, $npery = 0) + public static function NOMINAL($effectiveRate = 0, $periodsPerYear = 0) { - $effect_rate = Functions::flattenSingleValue($effect_rate); - $npery = (int) Functions::flattenSingleValue($npery); - - // Validate parameters - if ($effect_rate <= 0 || $npery < 1) { - return Functions::NAN(); - } - - // Calculate - return $npery * (($effect_rate + 1) ** (1 / $npery) - 1); + return InterestRate::nominal($effectiveRate, $periodsPerYear); } /** @@ -1754,7 +1525,7 @@ class Financial if (($rate <= 0) || ($yield <= 0)) { return Functions::NAN(); } - $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Financial\Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); if (!is_numeric($daysPerYear)) { return $daysPerYear; } @@ -2030,6 +1801,10 @@ class Financial * * Returns the bond-equivalent yield for a Treasury bill. * + * @Deprecated 1.18.0 + * + * @see Use the bondEquivalentYield() method in the Financial\TreasuryBill class instead + * * @param mixed $settlement The Treasury bill's settlement date. * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. * @param mixed $maturity The Treasury bill's maturity date. @@ -2040,37 +1815,21 @@ class Financial */ public static function TBILLEQ($settlement, $maturity, $discount) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $discount = Functions::flattenSingleValue($discount); - - // Use TBILLPRICE for validation - $testValue = self::TBILLPRICE($settlement, $maturity, $discount); - if (is_string($testValue)) { - return $testValue; - } - - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { - ++$maturity; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity) * 360; - } else { - $daysBetweenSettlementAndMaturity = (DateTime::getDateValue($maturity) - DateTime::getDateValue($settlement)); - } - - return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity); + return Financial\TreasuryBill::bondEquivalentYield($settlement, $maturity, $discount); } /** * TBILLPRICE. * - * Returns the yield for a Treasury bill. + * Returns the price per $100 face value for a Treasury bill. + * + * @Deprecated 1.18.0 + * + * @see Use the price() method in the Financial\TreasuryBill class instead * * @param mixed $settlement The Treasury bill's settlement date. - * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. + * The Treasury bill's settlement date is the date after the issue date + * 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 @@ -2079,44 +1838,7 @@ class Financial */ public static function TBILLPRICE($settlement, $maturity, $discount) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $discount = Functions::flattenSingleValue($discount); - - if (is_string($maturity = DateTime::getDateValue($maturity))) { - return Functions::VALUE(); - } - - // Validate - if (is_numeric($discount)) { - if ($discount <= 0) { - return Functions::NAN(); - } - - if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { - ++$maturity; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity) * 360; - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - } else { - $daysBetweenSettlementAndMaturity = (DateTime::getDateValue($maturity) - DateTime::getDateValue($settlement)); - } - - if ($daysBetweenSettlementAndMaturity > self::daysPerYear(DateTime::YEAR($maturity), 1)) { - return Functions::NAN(); - } - - $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); - if ($price <= 0) { - return Functions::NAN(); - } - - return $price; - } - - return Functions::VALUE(); + return Financial\TreasuryBill::price($settlement, $maturity, $discount); } /** @@ -2124,8 +1846,13 @@ class Financial * * Returns the yield for a Treasury bill. * + * @Deprecated 1.18.0 + * + * @see Use the yield() method in the Financial\TreasuryBill class instead + * * @param mixed $settlement The Treasury bill's settlement date. - * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. + * The Treasury bill's settlement date is the date after the issue date + * 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 @@ -2134,35 +1861,7 @@ class Financial */ public static function TBILLYIELD($settlement, $maturity, $price) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $price = Functions::flattenSingleValue($price); - - // Validate - if (is_numeric($price)) { - if ($price <= 0) { - return Functions::NAN(); - } - - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - ++$maturity; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity) * 360; - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - } else { - $daysBetweenSettlementAndMaturity = (DateTime::getDateValue($maturity) - DateTime::getDateValue($settlement)); - } - - if ($daysBetweenSettlementAndMaturity > 360) { - return Functions::NAN(); - } - - return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity); - } - - return Functions::VALUE(); + return Financial\TreasuryBill::yield($settlement, $maturity, $price); } private static function bothNegAndPos($neg, $pos) @@ -2407,7 +2106,7 @@ class Financial if (($price <= 0) || ($redemption <= 0)) { return Functions::NAN(); } - $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Financial\Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); if (!is_numeric($daysPerYear)) { return $daysPerYear; } @@ -2459,7 +2158,7 @@ class Financial if (($rate <= 0) || ($price <= 0)) { return Functions::NAN(); } - $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Financial\Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); if (!is_numeric($daysPerYear)) { return $daysPerYear; } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php new file mode 100644 index 00000000..ff99c839 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -0,0 +1,435 @@ +getMessage(); + } + + $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); + + if ($basis === Helpers::DAYS_PER_YEAR_ACTUAL) { + return abs(DateTime::DAYS($prev, $settlement)); + } + + return DateTime::YEARFRAC($prev, $settlement, $basis) * $daysPerYear; + } + + /** + * COUPDAYS. + * + * Returns the number of days in the coupon period that contains the settlement date. + * + * Excel Function: + * COUPDAYS(settlement,maturity,frequency[,basis]) + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string + */ + public static function COUPDAYS($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $frequency = Functions::flattenSingleValue($frequency); + $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateCouponPeriod($settlement, $maturity); + $frequency = self::validateFrequency($frequency); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + switch ($basis) { + case Helpers::DAYS_PER_YEAR_365: + // Actual/365 + return 365 / $frequency; + case Helpers::DAYS_PER_YEAR_ACTUAL: + // Actual/actual + if ($frequency == self::FREQUENCY_ANNUAL) { + $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + + return $daysPerYear / $frequency; + } + $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); + $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT); + + return $next - $prev; + default: + // US (NASD) 30/360, Actual/360 or European 30/360 + return 360 / $frequency; + } + } + + /** + * COUPDAYSNC. + * + * Returns the number of days from the settlement date to the next coupon date. + * + * Excel Function: + * COUPDAYSNC(settlement,maturity,frequency[,basis]) + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string + */ + public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $frequency = Functions::flattenSingleValue($frequency); + $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateCouponPeriod($settlement, $maturity); + $frequency = self::validateFrequency($frequency); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT); + + if ($basis === Helpers::DAYS_PER_YEAR_NASD) { + $settlementDate = Date::excelToDateTimeObject($settlement); + $settlementEoM = self::isLastDayOfMonth($settlementDate); + if ($settlementEoM) { + ++$settlement; + } + } + + return DateTime::YEARFRAC($settlement, $next, $basis) * $daysPerYear; + } + + /** + * COUPNCD. + * + * Returns the next coupon date after the settlement date. + * + * Excel Function: + * COUPNCD(settlement,maturity,frequency[,basis]) + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function COUPNCD($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $frequency = Functions::flattenSingleValue($frequency); + $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateCouponPeriod($settlement, $maturity); + $frequency = self::validateFrequency($frequency); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT); + } + + /** + * COUPNUM. + * + * Returns the number of coupons payable between the settlement date and maturity date, + * rounded up to the nearest whole coupon. + * + * Excel Function: + * COUPNUM(settlement,maturity,frequency[,basis]) + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return int|string + */ + public static function COUPNUM($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $frequency = Functions::flattenSingleValue($frequency); + $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateCouponPeriod($settlement, $maturity); + $frequency = self::validateFrequency($frequency); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + $yearsBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, 0); + + return ceil($yearsBetweenSettlementAndMaturity * $frequency); + } + + /** + * COUPPCD. + * + * Returns the previous coupon date before the settlement date. + * + * Excel Function: + * COUPPCD(settlement,maturity,frequency[,basis]) + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + public static function COUPPCD($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $frequency = Functions::flattenSingleValue($frequency); + $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateCouponPeriod($settlement, $maturity); + $frequency = self::validateFrequency($frequency); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); + } + + /** + * isLastDayOfMonth. + * + * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month + * + * @param \DateTime $testDate The date for testing + * + * @return bool + */ + private static function isLastDayOfMonth(\DateTime $testDate) + { + return $testDate->format('d') === $testDate->format('t'); + } + + private static function couponFirstPeriodDate($settlement, $maturity, int $frequency, $next) + { + $months = 12 / $frequency; + + $result = Date::excelToDateTimeObject($maturity); + $maturityEoM = self::isLastDayOfMonth($result); + + while ($settlement < Date::PHPToExcel($result)) { + $result->modify('-' . $months . ' months'); + } + if ($next === true) { + $result->modify('+' . $months . ' months'); + } + + if ($maturityEoM === true) { + $result->modify('-1 day'); + } + + return Date::PHPToExcel($result); + } + + private static function validateInputDate($date) + { + $date = DateTime::getDateValue($date); + if (is_string($date)) { + throw new Exception(Functions::VALUE()); + } + + return $date; + } + + private static function validateSettlementDate($settlement) + { + return self::validateInputDate($settlement); + } + + private static function validateMaturityDate($maturity) + { + return self::validateInputDate($maturity); + } + + private static function validateCouponPeriod($settlement, $maturity): void + { + if ($settlement >= $maturity) { + throw new Exception(Functions::NAN()); + } + } + + private static function validateFrequency($frequency): int + { + if (!is_numeric($frequency)) { + throw new Exception(Functions::NAN()); + } + + $frequency = (int) $frequency; + if ( + ($frequency !== self::FREQUENCY_ANNUAL) && + ($frequency !== self::FREQUENCY_SEMI_ANNUAL) && + ($frequency !== self::FREQUENCY_QUARTERLY) + ) { + throw new Exception(Functions::NAN()); + } + + return $frequency; + } + + private static function validateBasis($basis) + { + if (!is_numeric($basis)) { + throw new Exception(Functions::NAN()); + } + + $basis = (int) $basis; + if (($basis < 0) || ($basis > 4)) { + throw new Exception(Functions::NAN()); + } + + return $basis; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php new file mode 100644 index 00000000..e85b00c6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php @@ -0,0 +1,80 @@ + Helpers::daysPerYear(DateTime::YEAR($maturity), Helpers::DAYS_PER_YEAR_ACTUAL) || + $daysBetweenSettlementAndMaturity < 0 + ) { + return Functions::NAN(); + } + + return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity); + } + + return Functions::VALUE(); + } + + /** + * TBILLPRICE. + * + * Returns the price per $100 face value for a Treasury bill. + * + * @param mixed $settlement The Treasury bill's settlement date. + * The Treasury bill's settlement date is the date after the issue date + * 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 + * + * @return float|string Result, or a string containing an error + */ + public static function price($settlement, $maturity, $discount) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $discount = Functions::flattenSingleValue($discount); + + if ( + is_string($maturity = DateTime::getDateValue($maturity)) || + is_string($settlement = DateTime::getDateValue($settlement)) + ) { + return Functions::VALUE(); + } + + // Validate + if (is_numeric($discount)) { + if ($discount <= 0) { + return Functions::NAN(); + } + + $daysBetweenSettlementAndMaturity = $maturity - $settlement; + + if ( + $daysBetweenSettlementAndMaturity > Helpers::daysPerYear(DateTime::YEAR($maturity), Helpers::DAYS_PER_YEAR_ACTUAL) || + $daysBetweenSettlementAndMaturity < 0 + ) { + return Functions::NAN(); + } + $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); + if ($price < 0.0) { + return Functions::NAN(); + } + + return $price; + } + + return Functions::VALUE(); + } + + /** + * TBILLYIELD. + * + * Returns the yield for a Treasury bill. + * + * @param mixed $settlement The Treasury bill's settlement date. + * The Treasury bill's settlement date is the date after the issue date 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 + * + * @return float|string + */ + public static function yield($settlement, $maturity, $price) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $price = Functions::flattenSingleValue($price); + + if ( + is_string($maturity = DateTime::getDateValue($maturity)) || + is_string($settlement = DateTime::getDateValue($settlement)) + ) { + return Functions::VALUE(); + } + + // Validate + if (is_numeric($price)) { + if ($price <= 0) { + return Functions::NAN(); + } + + $daysBetweenSettlementAndMaturity = $maturity - $settlement; + + if ($daysBetweenSettlementAndMaturity > 360 || $daysBetweenSettlementAndMaturity < 0) { + return Functions::NAN(); + } + + return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity); + } + + return Functions::VALUE(); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php index 7c866ed4..fd8bb36f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php @@ -17,10 +17,12 @@ class EffectTest extends TestCase * @dataProvider providerEFFECT * * @param mixed $expectedResult + * @param mixed $rate + * @param mixed $periods */ - public function testEFFECT($expectedResult, ...$args): void + public function testEFFECT($expectedResult, $rate, $periods): void { - $result = Financial::EFFECT(...$args); + $result = Financial::EFFECT($rate, $periods); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php new file mode 100644 index 00000000..d8a5d7d0 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php @@ -0,0 +1,27 @@ + [ '#NUM!', '25-Jan-2007', '15-Nov-2008', 3, 1, ], + 'Non-Numeric Frequency' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 'NaN', + 1, + ], + 'Invalid Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + -1, + ], + 'Non-Numeric Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + 'NaN', + ], + 'Same Date' => [ + '#NUM!', + '24-Dec-2000', + '24-Dec-2000', + 4, + 0, + ], + [ + 311, + '31-Jan-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 317, + '31-Jan-2021', + '20-Mar-2021', + 1, + 1, + ], + [ + 317, + '31-Jan-2020', + '20-Mar-2021', + 1, + 1, + ], + [ + 317, + '31-Jan-2021', + '20-Mar-2021', + 1, + 2, + ], + [ + 317, + '31-Jan-2021', + '20-Mar-2021', + 1, + 3, + ], + [ + 310, + '31-Jan-2021', + '20-Mar-2021', + 1, + 4, + ], + [ + 131, + '31-Jan-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 133, + '31-Jan-2021', + '20-Mar-2021', + 2, + 1, + ], + [ + 133, + '31-Jan-2020', + '20-Mar-2021', + 2, + 1, + ], + [ + 133, + '31-Jan-2021', + '20-Mar-2021', + 2, + 2, + ], + [ + 133, + '31-Jan-2021', + '20-Mar-2021', + 2, + 3, + ], + [ + 130, + '31-Jan-2021', + '20-Mar-2021', + 2, + 4, + ], + [ + 41, + '31-Jan-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 42, + '31-Jan-2021', + '20-Mar-2021', + 4, + 1, + ], + [ + 42, + '31-Jan-2020', + '20-Mar-2021', + 4, + 1, + ], + [ + 42, + '31-Jan-2021', + '20-Mar-2021', + 4, + 2, + ], + [ + 42, + '31-Jan-2021', + '20-Mar-2021', + 4, + 3, + ], + [ + 40, + '31-Jan-2021', + '20-Mar-2021', + 4, + 4, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPDAYS.php b/tests/data/Calculation/Financial/COUPDAYS.php index 384df0f1..acec49d9 100644 --- a/tests/data/Calculation/Financial/COUPDAYS.php +++ b/tests/data/Calculation/Financial/COUPDAYS.php @@ -51,11 +51,165 @@ return [ 2, 1, ], - [ + 'Invalid Frequency' => [ '#NUM!', '25-Jan-2007', '15-Nov-2008', 3, 1, ], + 'Non-Numeric Frequency' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 'NaN', + 1, + ], + 'Invalid Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + -1, + ], + 'Non-Numeric Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + 'NaN', + ], + 'Same Date' => [ + '#NUM!', + '24-Dec-2000', + '24-Dec-2000', + 4, + 0, + ], + [ + 360, + '31-Jan-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 365, + '31-Jan-2021', + '20-Mar-2021', + 1, + 1, + ], + [ + 366, + '31-Jan-2020', + '20-Mar-2021', + 1, + 1, + ], + [ + 360, + '31-Jan-2021', + '20-Mar-2021', + 1, + 2, + ], + [ + 365, + '31-Jan-2021', + '20-Mar-2021', + 1, + 3, + ], + [ + 360, + '31-Jan-2021', + '20-Mar-2021', + 1, + 4, + ], + [ + 180, + '31-Jan-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 181, + '31-Jan-2021', + '20-Mar-2021', + 2, + 1, + ], + [ + 182, + '31-Jan-2020', + '20-Mar-2021', + 2, + 1, + ], + [ + 180, + '31-Jan-2021', + '20-Mar-2021', + 2, + 2, + ], + [ + 182.5, + '31-Jan-2021', + '20-Mar-2021', + 2, + 3, + ], + [ + 180, + '31-Jan-2021', + '20-Mar-2021', + 2, + 4, + ], + [ + 90, + '31-Jan-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 90, + '31-Jan-2021', + '20-Mar-2021', + 4, + 1, + ], + [ + 91, + '31-Jan-2020', + '20-Mar-2021', + 4, + 1, + ], + [ + 90, + '31-Jan-2021', + '20-Mar-2021', + 4, + 2, + ], + [ + 91.25, + '31-Jan-2021', + '20-Mar-2021', + 4, + 3, + ], + [ + 90, + '31-Jan-2021', + '20-Mar-2021', + 4, + 4, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPDAYSNC.php b/tests/data/Calculation/Financial/COUPDAYSNC.php index 2b249cb8..87951dd1 100644 --- a/tests/data/Calculation/Financial/COUPDAYSNC.php +++ b/tests/data/Calculation/Financial/COUPDAYSNC.php @@ -30,11 +30,186 @@ return [ 2, 1, ], - [ + 'Invalid Frequency' => [ '#NUM!', '25-Jan-2007', '15-Nov-2008', 3, 1, ], + 'Non-Numeric Frequency' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 'NaN', + 1, + ], + 'Invalid Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + -1, + ], + 'Non-Numeric Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + 'NaN', + ], + 'Same Date' => [ + '#NUM!', + '24-Dec-2000', + '24-Dec-2000', + 4, + 0, + ], + [ + 49, + '31-Jan-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 49, + '01-Feb-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 1, + 1, + ], + [ + 49, + '31-Jan-2020', + '20-Mar-2021', + 1, + 1, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 1, + 2, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 1, + 3, + ], + [ + 50, + '31-Jan-2021', + '20-Mar-2021', + 1, + 4, + ], + [ + 49, + '31-Jan-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 49, + '01-Feb-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 2, + 1, + ], + [ + 49, + '31-Jan-2020', + '20-Mar-2021', + 2, + 1, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 2, + 2, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 2, + 3, + ], + [ + 50, + '31-Jan-2021', + '20-Mar-2021', + 2, + 4, + ], + [ + 49, + '31-Jan-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 49, + '01-Feb-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 4, + 1, + ], + [ + 49, + '31-Jan-2020', + '20-Mar-2021', + 4, + 1, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 4, + 2, + ], + [ + 48, + '31-Jan-2021', + '20-Mar-2021', + 4, + 3, + ], + [ + 50, + '31-Jan-2021', + '20-Mar-2021', + 4, + 4, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPNCD.php b/tests/data/Calculation/Financial/COUPNCD.php index eea6ad13..e3d452e5 100644 --- a/tests/data/Calculation/Financial/COUPNCD.php +++ b/tests/data/Calculation/Financial/COUPNCD.php @@ -30,14 +30,35 @@ return [ 2, 1, ], - [ + 'Invalid Frequency' => [ '#NUM!', '25-Jan-2007', '15-Nov-2008', 3, 1, ], - [ + 'Non-Numeric Frequency' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 'NaN', + 1, + ], + 'Invalid Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + -1, + ], + 'Non-Numeric Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + 'NaN', + ], + 'Same Date' => [ '#NUM!', '24-Dec-2000', '24-Dec-2000', @@ -65,4 +86,130 @@ return [ 4, 0, ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 1, + 1, + ], + [ + 43910, + '31-Jan-2020', + '20-Mar-2021', + 1, + 1, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 1, + 2, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 1, + 3, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 1, + 4, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 2, + 1, + ], + [ + 43910, + '31-Jan-2020', + '20-Mar-2021', + 2, + 1, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 2, + 2, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 2, + 3, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 2, + 4, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 4, + 1, + ], + [ + 43910, + '31-Jan-2020', + '20-Mar-2021', + 4, + 1, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 4, + 2, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 4, + 3, + ], + [ + 44275, + '31-Jan-2021', + '20-Mar-2021', + 4, + 4, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPNUM.php b/tests/data/Calculation/Financial/COUPNUM.php index 719ad733..b9ad73fa 100644 --- a/tests/data/Calculation/Financial/COUPNUM.php +++ b/tests/data/Calculation/Financial/COUPNUM.php @@ -31,13 +31,41 @@ return [ 2, 1, ], - [ + 'Invalid Frequency' => [ '#NUM!', '25-Jan-2007', '15-Nov-2008', 3, 1, ], + 'Non-Numeric Frequency' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 'NaN', + 1, + ], + 'Invalid Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + -1, + ], + 'Non-Numeric Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + 'NaN', + ], + 'Same Date' => [ + '#NUM!', + '24-Dec-2000', + '24-Dec-2000', + 4, + 0, + ], [ 5, '01-Jan-2008', @@ -108,4 +136,130 @@ return [ 2, 4, ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 1, + 1, + ], + [ + 2, + '31-Jan-2020', + '20-Mar-2021', + 1, + 1, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 1, + 2, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 1, + 3, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 1, + 4, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 2, + 1, + ], + [ + 3, + '31-Jan-2020', + '20-Mar-2021', + 2, + 1, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 2, + 2, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 2, + 3, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 2, + 4, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 4, + 1, + ], + [ + 5, + '31-Jan-2020', + '20-Mar-2021', + 4, + 1, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 4, + 2, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 4, + 3, + ], + [ + 1, + '31-Jan-2021', + '20-Mar-2021', + 4, + 4, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPPCD.php b/tests/data/Calculation/Financial/COUPPCD.php index 911637d6..6d2e2f22 100644 --- a/tests/data/Calculation/Financial/COUPPCD.php +++ b/tests/data/Calculation/Financial/COUPPCD.php @@ -30,14 +30,35 @@ return [ 2, 1, ], - [ + 'Invalid Frequency' => [ '#NUM!', '25-Jan-2007', '15-Nov-2008', 3, 1, ], - [ + 'Non-Numeric Frequency' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 'NaN', + 1, + ], + 'Invalid Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + -1, + ], + 'Non-Numeric Basis' => [ + '#NUM!', + '25-Jan-2007', + '15-Nov-2008', + 4, + 'NaN', + ], + 'Same Date' => [ '#NUM!', '24-Dec-2000', '24-Dec-2000', @@ -65,4 +86,130 @@ return [ 4, 0, ], + [ + 43910, + '31-Jan-2021', + '20-Mar-2021', + 1, + 0, + ], + [ + 43910, + '31-Jan-2021', + '20-Mar-2021', + 1, + 1, + ], + [ + 43544, + '31-Jan-2020', + '20-Mar-2021', + 1, + 1, + ], + [ + 43910, + '31-Jan-2021', + '20-Mar-2021', + 1, + 2, + ], + [ + 43910, + '31-Jan-2021', + '20-Mar-2021', + 1, + 3, + ], + [ + 43910, + '31-Jan-2021', + '20-Mar-2021', + 1, + 4, + ], + [ + 44094, + '31-Jan-2021', + '20-Mar-2021', + 2, + 0, + ], + [ + 44094, + '31-Jan-2021', + '20-Mar-2021', + 2, + 1, + ], + [ + 43728, + '31-Jan-2020', + '20-Mar-2021', + 2, + 1, + ], + [ + 44094, + '31-Jan-2021', + '20-Mar-2021', + 2, + 2, + ], + [ + 44094, + '31-Jan-2021', + '20-Mar-2021', + 2, + 3, + ], + [ + 44094, + '31-Jan-2021', + '20-Mar-2021', + 2, + 4, + ], + [ + 44185, + '31-Jan-2021', + '20-Mar-2021', + 4, + 0, + ], + [ + 44185, + '31-Jan-2021', + '20-Mar-2021', + 4, + 1, + ], + [ + 43819, + '31-Jan-2020', + '20-Mar-2021', + 4, + 1, + ], + [ + 44185, + '31-Jan-2021', + '20-Mar-2021', + 4, + 2, + ], + [ + 44185, + '31-Jan-2021', + '20-Mar-2021', + 4, + 3, + ], + [ + 44185, + '31-Jan-2021', + '20-Mar-2021', + 4, + 4, + ], ]; diff --git a/tests/data/Calculation/Financial/DaysPerYear.php b/tests/data/Calculation/Financial/DaysPerYear.php new file mode 100644 index 00000000..f9ca1c1d --- /dev/null +++ b/tests/data/Calculation/Financial/DaysPerYear.php @@ -0,0 +1,15 @@ + Date: Sat, 20 Mar 2021 22:52:04 +0100 Subject: [PATCH 127/187] First pass at extracting Financial Price functions for Securities (#1942) * Extracting Financial Price functions for Securities - PRICE(), PRICEMAT(), PRICEDISC() * Additional unit tests for PRICEDISC() invalid arguments * Additional unit tests for PRICEMAT() invalid arguments * Add docblock for PRICE() * Clarification on validation checks for <= 0 and < 0 --- .../Calculation/Calculation.php | 6 +- src/PhpSpreadsheet/Calculation/Financial.php | 183 +++------- .../Calculation/Financial/Coupons.php | 2 +- .../Calculation/Financial/Securities.php | 321 ++++++++++++++++++ .../data/Calculation/Financial/PRICEDISC.php | 32 ++ tests/data/Calculation/Financial/PRICEMAT.php | 28 ++ 6 files changed, 426 insertions(+), 146 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 05fe8a81..36f5efe4 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1983,17 +1983,17 @@ class Calculation ], 'PRICE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PRICE'], + 'functionCall' => [Financial\Securities::class, 'price'], 'argumentCount' => '6,7', ], 'PRICEDISC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PRICEDISC'], + 'functionCall' => [Financial\Securities::class, 'discounted'], 'argumentCount' => '4,5', ], 'PRICEMAT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PRICEMAT'], + 'functionCall' => [Financial\Securities::class, 'maturity'], 'argumentCount' => '5,6', ], 'PROB' => [ diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index f6f5c775..9735e9f4 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -11,15 +11,6 @@ class Financial const FINANCIAL_PRECISION = 1.0e-08; - private static function isValidFrequency($frequency) - { - if (($frequency == 1) || ($frequency == 2) || ($frequency == 4)) { - return true; - } - - return false; - } - private static function interestAndPrincipal($rate = 0, $per = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) { $pmt = self::PMT($rate, $nper, $pv, $fv, $type); @@ -1370,79 +1361,39 @@ class Financial return $interestAndPrincipal[1]; } - private static function validatePrice($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis) - { - if (is_string($settlement)) { - return Functions::VALUE(); - } - if (is_string($maturity)) { - return Functions::VALUE(); - } - if (!is_numeric($rate)) { - return Functions::VALUE(); - } - if (!is_numeric($yield)) { - return Functions::VALUE(); - } - if (!is_numeric($redemption)) { - return Functions::VALUE(); - } - if (!is_numeric($frequency)) { - return Functions::VALUE(); - } - if (!is_numeric($basis)) { - return Functions::VALUE(); - } - - return ''; - } - + /** + * PRICE. + * + * Returns the price per $100 face value of a security that pays periodic interest. + * + * @Deprecated 1.18.0 + * + * @see Use the price() method in the Financial\Securities class instead + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue 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 float $rate the security's annual coupon rate + * @param float $yield the security's annual yield + * @param float $redemption The number of coupon payments per year. + * For annual payments, frequency = 1; + * for semiannual, frequency = 2; + * for quarterly, frequency = 4. + * @param int $frequency + * @param int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string Result, or a string containing an error + */ public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $rate = Functions::flattenSingleValue($rate); - $yield = Functions::flattenSingleValue($yield); - $redemption = Functions::flattenSingleValue($redemption); - $frequency = Functions::flattenSingleValue($frequency); - $basis = Functions::flattenSingleValue($basis); - - $settlement = DateTime::getDateValue($settlement); - $maturity = DateTime::getDateValue($maturity); - $rslt = self::validatePrice($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis); - if ($rslt) { - return $rslt; - } - $rate = (float) $rate; - $yield = (float) $yield; - $redemption = (float) $redemption; - $frequency = (int) $frequency; - $basis = (int) $basis; - - if ( - ($settlement > $maturity) || - (!self::isValidFrequency($frequency)) || - (($basis < 0) || ($basis > 4)) - ) { - return Functions::NAN(); - } - - $dsc = self::COUPDAYSNC($settlement, $maturity, $frequency, $basis); - $e = self::COUPDAYS($settlement, $maturity, $frequency, $basis); - $n = self::COUPNUM($settlement, $maturity, $frequency, $basis); - $a = self::COUPDAYBS($settlement, $maturity, $frequency, $basis); - - $baseYF = 1.0 + ($yield / $frequency); - $rfp = 100 * ($rate / $frequency); - $de = $dsc / $e; - - $result = $redemption / $baseYF ** (--$n + $de); - for ($k = 0; $k <= $n; ++$k) { - $result += $rfp / ($baseYF ** ($k + $de)); - } - $result -= $rfp * ($a / $e); - - return $result; + return Financial\Securities::price($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis); } /** @@ -1450,6 +1401,10 @@ class Financial * * Returns the price per $100 face value of a discounted security. * + * @Deprecated 1.18.0 + * + * @see Use the discounted() method in the Financial\Securities class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date when the security is traded to the buyer. * @param mixed $maturity The security's maturity date. @@ -1467,27 +1422,7 @@ class Financial */ public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $discount = (float) Functions::flattenSingleValue($discount); - $redemption = (float) Functions::flattenSingleValue($redemption); - $basis = (int) Functions::flattenSingleValue($basis); - - // Validate - if ((is_numeric($discount)) && (is_numeric($redemption)) && (is_numeric($basis))) { - if (($discount <= 0) || ($redemption <= 0)) { - return Functions::NAN(); - } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - - return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity); - } - - return Functions::VALUE(); + return Financial\Securities::discounted($settlement, $maturity, $discount, $redemption, $basis); } /** @@ -1495,6 +1430,10 @@ class Financial * * Returns the price per $100 face value of a security that pays interest at maturity. * + * @Deprecated 1.18.0 + * + * @see Use the maturity() method in the Financial\Securities class instead + * * @param mixed $settlement The security's settlement date. * The security's settlement date is the date after the issue date when the security is traded to the buyer. * @param mixed $maturity The security's maturity date. @@ -1513,47 +1452,7 @@ class Financial */ public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $issue = Functions::flattenSingleValue($issue); - $rate = Functions::flattenSingleValue($rate); - $yield = Functions::flattenSingleValue($yield); - $basis = (int) Functions::flattenSingleValue($basis); - - // Validate - if (is_numeric($rate) && is_numeric($yield)) { - if (($rate <= 0) || ($yield <= 0)) { - return Functions::NAN(); - } - $daysPerYear = Financial\Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); - if (!is_numeric($daysPerYear)) { - return $daysPerYear; - } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - // return date error - return $daysBetweenIssueAndSettlement; - } - $daysBetweenIssueAndSettlement *= $daysPerYear; - $daysBetweenIssueAndMaturity = DateTime::YEARFRAC($issue, $maturity, $basis); - if (!is_numeric($daysBetweenIssueAndMaturity)) { - // return date error - return $daysBetweenIssueAndMaturity; - } - $daysBetweenIssueAndMaturity *= $daysPerYear; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - $daysBetweenSettlementAndMaturity *= $daysPerYear; - - return (100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) / - (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) - - (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100); - } - - return Functions::VALUE(); + return Financial\Securities::maturity($settlement, $maturity, $issue, $rate, $yield, $basis); } /** diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php index ff99c839..835ef633 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -419,7 +419,7 @@ class Coupons return $frequency; } - private static function validateBasis($basis) + private static function validateBasis($basis): int { if (!is_numeric($basis)) { throw new Exception(Functions::NAN()); diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities.php b/src/PhpSpreadsheet/Calculation/Financial/Securities.php new file mode 100644 index 00000000..761fc18a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities.php @@ -0,0 +1,321 @@ +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); + + $baseYF = 1.0 + ($yield / $frequency); + $rfp = 100 * ($rate / $frequency); + $de = $dsc / $e; + + $result = $redemption / $baseYF ** (--$n + $de); + for ($k = 0; $k <= $n; ++$k) { + $result += $rfp / ($baseYF ** ($k + $de)); + } + $result -= $rfp * ($a / $e); + + return $result; + } + + /** + * PRICEDISC. + * + * Returns the price per $100 face value of a discounted security. + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue 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 float $discount The security's discount rate + * @param float $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 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string Result, or a string containing an error + */ + public static function discounted($settlement, $maturity, $discount, $redemption, $basis = 0) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $discount = Functions::flattenSingleValue($discount); + $redemption = Functions::flattenSingleValue($redemption); + $basis = Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateSecurityPeriod($settlement, $maturity); + $discount = self::validateDiscount($discount); + $redemption = self::validateRedemption($redemption); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return $redemption * (1 - $discount * $daysBetweenSettlementAndMaturity); + } + + /** + * PRICEMAT. + * + * Returns the price per $100 face value of a security that pays interest at maturity. + * + * @param mixed $settlement The security's settlement date. + * The security's settlement date is the date after the issue 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 mixed $issue The security's issue date + * @param float $rate The security's interest rate at date of issue + * @param float $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 + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string Result, or a string containing an error + */ + public static function maturity($settlement, $maturity, $issue, $rate, $yield, $basis = 0) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $issue = Functions::flattenSingleValue($issue); + $rate = Functions::flattenSingleValue($rate); + $yield = Functions::flattenSingleValue($yield); + $basis = Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateSecurityPeriod($settlement, $maturity); + $issue = self::validateIssueDate($issue); + $rate = self::validateRate($rate); + $yield = self::validateYield($yield); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + if (!is_numeric($daysPerYear)) { + return $daysPerYear; + } + $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + $daysBetweenIssueAndSettlement *= $daysPerYear; + $daysBetweenIssueAndMaturity = DateTime::YEARFRAC($issue, $maturity, $basis); + if (!is_numeric($daysBetweenIssueAndMaturity)) { + // return date error + return $daysBetweenIssueAndMaturity; + } + $daysBetweenIssueAndMaturity *= $daysPerYear; + $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + $daysBetweenSettlementAndMaturity *= $daysPerYear; + + return (100 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate * 100)) / + (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) - + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100); + } + + private static function validateInputDate($date) + { + $date = DateTime::getDateValue($date); + if (is_string($date)) { + throw new Exception(Functions::VALUE()); + } + + return $date; + } + + private static function validateSettlementDate($settlement) + { + return self::validateInputDate($settlement); + } + + private static function validateMaturityDate($maturity) + { + return self::validateInputDate($maturity); + } + + private static function validateIssueDate($issue) + { + return self::validateInputDate($issue); + } + + private static function validateSecurityPeriod($settlement, $maturity): void + { + if ($settlement >= $maturity) { + throw new Exception(Functions::NAN()); + } + } + + private static function validateRate($rate): float + { + if (!is_numeric($rate)) { + throw new Exception(Functions::VALUE()); + } + + $rate = (float) $rate; + if ($rate < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $rate; + } + + private static function validateYield($yield): float + { + if (!is_numeric($yield)) { + throw new Exception(Functions::VALUE()); + } + + $yield = (float) $yield; + if ($yield < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $yield; + } + + private static function validateRedemption($redemption): float + { + if (!is_numeric($redemption)) { + throw new Exception(Functions::VALUE()); + } + + $redemption = (float) $redemption; + if ($redemption <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $redemption; + } + + private static function validateDiscount($discount): float + { + if (!is_numeric($discount)) { + throw new Exception(Functions::VALUE()); + } + + $discount = (float) $discount; + if ($discount <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $discount; + } + + private static function validateFrequency($frequency): int + { + if (!is_numeric($frequency)) { + throw new Exception(Functions::VALUE()); + } + + $frequency = (int) $frequency; + if ( + ($frequency !== self::FREQUENCY_ANNUAL) && + ($frequency !== self::FREQUENCY_SEMI_ANNUAL) && + ($frequency !== self::FREQUENCY_QUARTERLY) + ) { + throw new Exception(Functions::NAN()); + } + + return $frequency; + } + + private static function validateBasis($basis): int + { + if (!is_numeric($basis)) { + throw new Exception(Functions::VALUE()); + } + + $basis = (int) $basis; + if (($basis < 0) || ($basis > 4)) { + throw new Exception(Functions::NAN()); + } + + return $basis; + } +} diff --git a/tests/data/Calculation/Financial/PRICEDISC.php b/tests/data/Calculation/Financial/PRICEDISC.php index 88a0d94e..9413ca39 100644 --- a/tests/data/Calculation/Financial/PRICEDISC.php +++ b/tests/data/Calculation/Financial/PRICEDISC.php @@ -9,4 +9,36 @@ return [ 97.6311475409836, ['2008-02-15', '2008-11-30', 0.03, 100, 1], ], + [ + '#VALUE!', + ['Invalid Date', '2008-11-30', 0.03, 100, 1], + ], + [ + '#VALUE!', + ['2008-02-15', 'Invalid Date', 0.03, 100, 1], + ], + [ + '#VALUE!', + ['2008-02-15', '2008-11-30', 'NaN', 100, 1], + ], + [ + '#NUM!', + ['2008-02-15', '2008-11-30', -0.03, 100, 1], + ], + [ + '#VALUE!', + ['2008-02-15', '2008-11-30', 0.03, 'NaN', 1], + ], + [ + '#NUM!', + ['2008-02-15', '2008-11-30', 0.03, -100, 1], + ], + [ + '#VALUE!', + ['2008-02-15', '2008-11-30', 0.03, 100, 'NaN'], + ], + [ + '#NUM!', + ['2008-02-15', '2008-11-30', 0.03, 100, -1], + ], ]; diff --git a/tests/data/Calculation/Financial/PRICEMAT.php b/tests/data/Calculation/Financial/PRICEMAT.php index ac5c242e..2de50927 100644 --- a/tests/data/Calculation/Financial/PRICEMAT.php +++ b/tests/data/Calculation/Financial/PRICEMAT.php @@ -13,4 +13,32 @@ return [ 93.0909090909091, '1-Jul-2017', '1-Jan-2027', '1-Jan-2017', 0.07, 0.08, ], + [ + '#VALUE!', + 'Invalid Date', '1-Jan-2027', '1-Jan-2017', 0.07, 0.08, + ], + [ + '#VALUE!', + '1-Jul-2017', 'Invalid Date', '1-Jan-2017', 0.07, 0.08, + ], + [ + '#VALUE!', + '1-Jul-2017', '1-Jan-2027', 'Invalid Date', 0.07, 0.08, + ], + [ + '#VALUE!', + '1-Jul-2017', '1-Jan-2027', '1-Jan-2017', 'NaN', 0.08, + ], + [ + '#NUM!', + '1-Jul-2017', '1-Jan-2027', '1-Jan-2017', -0.07, 0.08, + ], + [ + '#VALUE!', + '1-Jul-2017', '1-Jan-2027', '1-Jan-2017', 0.07, 'NaN', + ], + [ + '#NUM!', + '1-Jul-2017', '1-Jan-2027', '1-Jan-2017', 0.07, -0.08, + ], ]; From 9beacd21be4725bc2a73aebd3b74df75b7658d09 Mon Sep 17 00:00:00 2001 From: oleibman Date: Sun, 21 Mar 2021 01:12:05 -0700 Subject: [PATCH 128/187] Complete Breakup Of Calculation/DateTime Functions (#1937) * Complete Breakup Of Calculation/DateTime Functions In conjunction with parallel breakups happening in other areas of Calculation, this change breaks up all the DateTime functions into their own classes. All methods remaining in DateTime itself have a doc block deprecation notice, and consist only of stub code to call the replacement methods. Coverage of DateTime itself and all the replacement methods is 100%. There is only one substantive change to the code (see next paragraph). Among the non-substantive changes, it now adopts the same parsing technique (throwing and catching exceptions) already in use in Engineering and MathTrig. Boolean parameters are allowed in lieu of numbers when Excel allows them. Most of the code changes involve refactoring due to the need to avoid Scrutinizer "complexity" failures in what it will consider to be new methods. Issue #1936 was opened just as I was staging this. It is now fixed. One existing WORKDAY test was wrong (noted in a comment in the test data file), and a bunch of new tests are added. I found it confusing to use DateTime as a node of the the class name since most of the methods invoke native DateTime methods. So, everything is moved to directory DateTimeExcel, and that is what is used in the class names. There are several follow-up activities that I am planning to undertake if this PR is merged. - ODS supports dates well before 1900. There are exactly 2 assertions for this functionality. More are needed (and some functions might have to change to accept this). - WEEKDAY has some poorly documented extra options for "style" which are not yet implemented. - Most tests have been changed to use a formula as entered on a spreadsheet rather than a direct call to the method which implements the formula. There are 3 exceptions at this time. WORKDAY and NETWORKDAYS, which include arrays as part of their parameters, are more complicated than most. YEARFRAC was just too large to deal with now. - There are direct calls to the now-deprecated methods in both source code and tests, mostly in Financial code, but possibly in others as well. These need to be changed. - Some constants, none "officially" documented, remain in the original class. These should be either deleted or marked deprecated. I wasn't sure if deprecation was even possible (or desirable), and did not want that to be something which would cause Scrutinizer to fail the change. * Deprecate Now-unused Constants, Fix Yearfrac bug, Change 3 Tests Add new DateTime/Constants class, initially populated with constants used in Weeknum. MS has another inconsistency with how it handles null cells in Yearfrac. Change PhpSpreadsheet to behave compatibly with this bug. I have modified YearFrac, WorkDay, and NetworkDays tests to be more to my liking. Many tests added to YearFrac because of the bug above. Only minor modifications to the existing tests for the others. --- .../Calculation/Calculation.php | 46 +- src/PhpSpreadsheet/Calculation/DateTime.php | 1291 +++-------------- .../Calculation/DateTimeExcel/Constants.php | 37 + .../Calculation/DateTimeExcel/DateDif.php | 146 ++ .../Calculation/DateTimeExcel/DateValue.php | 151 ++ .../Calculation/DateTimeExcel/Datefunc.php | 168 +++ .../Calculation/DateTimeExcel/Day.php | 61 + .../Calculation/DateTimeExcel/Days.php | 51 + .../Calculation/DateTimeExcel/Days360.php | 106 ++ .../Calculation/DateTimeExcel/EDate.php | 45 + .../Calculation/DateTimeExcel/EoMonth.php | 47 + .../Calculation/DateTimeExcel/Helpers.php | 291 ++++ .../Calculation/DateTimeExcel/Hour.php | 44 + .../Calculation/DateTimeExcel/IsoWeekNum.php | 55 + .../Calculation/DateTimeExcel/Minute.php | 44 + .../Calculation/DateTimeExcel/Month.php | 40 + .../Calculation/DateTimeExcel/NetworkDays.php | 102 ++ .../Calculation/DateTimeExcel/Now.php | 34 + .../Calculation/DateTimeExcel/Second.php | 44 + .../Calculation/DateTimeExcel/Time.php | 116 ++ .../Calculation/DateTimeExcel/TimeValue.php | 61 + .../Calculation/DateTimeExcel/Today.php | 34 + .../Calculation/DateTimeExcel/WeekDay.php | 80 + .../Calculation/DateTimeExcel/WeekNum.php | 130 ++ .../Calculation/DateTimeExcel/WorkDay.php | 182 +++ .../Calculation/DateTimeExcel/Year.php | 40 + .../Calculation/DateTimeExcel/YearFrac.php | 120 ++ .../Functions/DateTime/AllSetupTeardown.php | 71 + .../Functions/DateTime/DateDifTest.php | 26 +- .../Functions/DateTime/DateTest.php | 56 +- .../Functions/DateTime/DateValueTest.php | 53 +- .../Functions/DateTime/DayTest.php | 65 +- .../Functions/DateTime/Days360Test.php | 27 +- .../Functions/DateTime/DaysTest.php | 43 +- .../Functions/DateTime/EDateTest.php | 33 +- .../Functions/DateTime/EoMonthTest.php | 36 +- .../Functions/DateTime/HourTest.php | 24 +- .../Functions/DateTime/IsoWeekNumTest.php | 44 +- .../Functions/DateTime/MinuteTest.php | 24 +- .../Functions/DateTime/MonthTest.php | 24 +- .../Functions/DateTime/MovedFunctionsTest.php | 63 + .../Functions/DateTime/NetworkDaysTest.php | 50 +- .../Functions/DateTime/NowTest.php | 8 +- .../Functions/DateTime/SecondTest.php | 24 +- .../Functions/DateTime/TimeTest.php | 52 +- .../Functions/DateTime/TimeValueTest.php | 28 +- .../Functions/DateTime/TodayTest.php | 34 + .../Functions/DateTime/WeekDayTest.php | 35 +- .../Functions/DateTime/WeekNumTest.php | 51 +- .../Functions/DateTime/WorkDayTest.php | 50 +- .../Functions/DateTime/YearFracTest.php | 42 +- .../Functions/DateTime/YearTest.php | 24 +- tests/data/Calculation/DateTime/DATE.php | 393 +---- tests/data/Calculation/DateTime/DATEDIF.php | 528 ++----- tests/data/Calculation/DateTime/DATEVALUE.php | 379 +---- tests/data/Calculation/DateTime/DAY.php | 81 +- .../Calculation/DateTime/DAYOpenOffice.php | 19 + tests/data/Calculation/DateTime/DAYS.php | 97 +- tests/data/Calculation/DateTime/DAYS360.php | 174 +-- tests/data/Calculation/DateTime/EDATE.php | 80 +- tests/data/Calculation/DateTime/EOMONTH.php | 92 +- tests/data/Calculation/DateTime/HOUR.php | 65 +- .../data/Calculation/DateTime/ISOWEEKNUM.php | 69 +- .../Calculation/DateTime/ISOWEEKNUM1904.php | 33 + tests/data/Calculation/DateTime/MINUTE.php | 65 +- tests/data/Calculation/DateTime/MONTH.php | 68 +- .../data/Calculation/DateTime/NETWORKDAYS.php | 19 +- tests/data/Calculation/DateTime/SECOND.php | 65 +- tests/data/Calculation/DateTime/TIME.php | 112 +- tests/data/Calculation/DateTime/TIMEVALUE.php | 70 +- tests/data/Calculation/DateTime/WEEKDAY.php | 156 +- tests/data/Calculation/DateTime/WEEKNUM.php | 275 +--- .../data/Calculation/DateTime/WEEKNUM1904.php | 92 ++ tests/data/Calculation/DateTime/WORKDAY.php | 28 +- tests/data/Calculation/DateTime/YEAR.php | 62 +- tests/data/Calculation/DateTime/YEARFRAC.php | 50 + 76 files changed, 3874 insertions(+), 3751 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Constants.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Datefunc.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Day.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/EDate.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/EoMonth.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Hour.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/IsoWeekNum.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Minute.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Now.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Second.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Today.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/Year.php create mode 100644 src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MovedFunctionsTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TodayTest.php create mode 100644 tests/data/Calculation/DateTime/DAYOpenOffice.php create mode 100644 tests/data/Calculation/DateTime/ISOWEEKNUM1904.php create mode 100644 tests/data/Calculation/DateTime/WEEKNUM1904.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 36f5efe4..dbea0850 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -755,17 +755,17 @@ class Calculation ], 'DATE' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DATE'], + 'functionCall' => [DateTimeExcel\Datefunc::class, 'funcDate'], 'argumentCount' => '3', ], 'DATEDIF' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DATEDIF'], + 'functionCall' => [DateTimeExcel\DateDif::class, 'funcDateDif'], 'argumentCount' => '2,3', ], 'DATEVALUE' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DATEVALUE'], + 'functionCall' => [DateTimeExcel\DateValue::class, 'funcDateValue'], 'argumentCount' => '1', ], 'DAVERAGE' => [ @@ -775,17 +775,17 @@ class Calculation ], 'DAY' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DAYOFMONTH'], + 'functionCall' => [DateTimeExcel\Day::class, 'funcDay'], 'argumentCount' => '1', ], 'DAYS' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DAYS'], + 'functionCall' => [DateTimeExcel\Days::class, 'funcDays'], 'argumentCount' => '2', ], 'DAYS360' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DAYS360'], + 'functionCall' => [DateTimeExcel\Days360::class, 'funcDays360'], 'argumentCount' => '2,3', ], 'DB' => [ @@ -920,7 +920,7 @@ class Calculation ], 'EDATE' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'EDATE'], + 'functionCall' => [DateTimeExcel\EDate::class, 'funcEDate'], 'argumentCount' => '2', ], 'EFFECT' => [ @@ -935,7 +935,7 @@ class Calculation ], 'EOMONTH' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'EOMONTH'], + 'functionCall' => [DateTimeExcel\EoMonth::class, 'funcEoMonth'], 'argumentCount' => '2', ], 'ERF' => [ @@ -1237,7 +1237,7 @@ class Calculation ], 'HOUR' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'HOUROFDAY'], + 'functionCall' => [DateTimeExcel\Hour::class, 'funcHour'], 'argumentCount' => '1', ], 'HYPERLINK' => [ @@ -1501,7 +1501,7 @@ class Calculation ], 'ISOWEEKNUM' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'ISOWEEKNUM'], + 'functionCall' => [DateTimeExcel\IsoWeekNum::class, 'funcIsoWeekNum'], 'argumentCount' => '1', ], 'ISPMT' => [ @@ -1681,7 +1681,7 @@ class Calculation ], 'MINUTE' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'MINUTE'], + 'functionCall' => [DateTimeExcel\Minute::class, 'funcMinute'], 'argumentCount' => '1', ], 'MINVERSE' => [ @@ -1721,7 +1721,7 @@ class Calculation ], 'MONTH' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'MONTHOFYEAR'], + 'functionCall' => [DateTimeExcel\Month::class, 'funcMonth'], 'argumentCount' => '1', ], 'MROUND' => [ @@ -1761,7 +1761,7 @@ class Calculation ], 'NETWORKDAYS' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'NETWORKDAYS'], + 'functionCall' => [DateTimeExcel\NetworkDays::class, 'funcNetworkDays'], 'argumentCount' => '2-3', ], 'NETWORKDAYS.INTL' => [ @@ -1821,7 +1821,7 @@ class Calculation ], 'NOW' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DATETIMENOW'], + 'functionCall' => [DateTimeExcel\Now::class, 'funcNow'], 'argumentCount' => '0', ], 'NPER' => [ @@ -2175,7 +2175,7 @@ class Calculation ], 'SECOND' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'SECOND'], + 'functionCall' => [DateTimeExcel\Second::class, 'funcSecond'], 'argumentCount' => '1', ], 'SEQUENCE' => [ @@ -2421,12 +2421,12 @@ class Calculation ], 'TIME' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'TIME'], + 'functionCall' => [DateTimeExcel\Time::class, 'funcTime'], 'argumentCount' => '3', ], 'TIMEVALUE' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'TIMEVALUE'], + 'functionCall' => [DateTimeExcel\TimeValue::class, 'funcTimeValue'], 'argumentCount' => '1', ], 'TINV' => [ @@ -2446,7 +2446,7 @@ class Calculation ], 'TODAY' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'DATENOW'], + 'functionCall' => [DateTimeExcel\Today::class, 'funcToday'], 'argumentCount' => '0', ], 'TRANSPOSE' => [ @@ -2571,12 +2571,12 @@ class Calculation ], 'WEEKDAY' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'WEEKDAY'], + 'functionCall' => [DateTimeExcel\WeekDay::class, 'funcWeekDay'], 'argumentCount' => '1,2', ], 'WEEKNUM' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'WEEKNUM'], + 'functionCall' => [DateTimeExcel\WeekNum::class, 'funcWeekNum'], 'argumentCount' => '1,2', ], 'WEIBULL' => [ @@ -2591,7 +2591,7 @@ class Calculation ], 'WORKDAY' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'WORKDAY'], + 'functionCall' => [DateTimeExcel\WorkDay::class, 'funcWorkDay'], 'argumentCount' => '2-3', ], 'WORKDAY.INTL' => [ @@ -2626,12 +2626,12 @@ class Calculation ], 'YEAR' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'YEAR'], + 'functionCall' => [DateTimeExcel\Year::class, 'funcYear'], 'argumentCount' => '1', ], 'YEARFRAC' => [ 'category' => Category::CATEGORY_DATE_AND_TIME, - 'functionCall' => [DateTime::class, 'YEARFRAC'], + 'functionCall' => [DateTimeExcel\YearFrac::class, 'funcYearFrac'], 'argumentCount' => '2,3', ], 'YIELD' => [ diff --git a/src/PhpSpreadsheet/Calculation/DateTime.php b/src/PhpSpreadsheet/Calculation/DateTime.php index 64d72c2b..744d9589 100644 --- a/src/PhpSpreadsheet/Calculation/DateTime.php +++ b/src/PhpSpreadsheet/Calculation/DateTime.php @@ -2,127 +2,36 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; -use DateTimeImmutable; use DateTimeInterface; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PhpOffice\PhpSpreadsheet\Shared\StringHelper; class DateTime { /** * Identify if a year is a leap year or not. * + * @Deprecated 2.0.0 Use the method isLeapYear in the DateTimeExcel\Helpers class instead + * * @param int|string $year The year to test * * @return bool TRUE if the year is a leap year, otherwise FALSE */ public static function isLeapYear($year) { - return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0); - } - - /** - * Return the number of days between two dates based on a 360 day calendar. - * - * @param int $startDay Day of month of the start date - * @param int $startMonth Month of the start date - * @param int $startYear Year of the start date - * @param int $endDay Day of month of the start date - * @param int $endMonth Month of the start date - * @param int $endYear Year of the start date - * @param bool $methodUS Whether to use the US method or the European method of calculation - * - * @return int Number of days between the start date and the end date - */ - private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS) - { - if ($startDay == 31) { - --$startDay; - } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) { - $startDay = 30; - } - if ($endDay == 31) { - if ($methodUS && $startDay != 30) { - $endDay = 1; - if ($endMonth == 12) { - ++$endYear; - $endMonth = 1; - } else { - ++$endMonth; - } - } else { - $endDay = 30; - } - } - - return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360; + return DateTimeExcel\Helpers::isLeapYear($year); } /** * getDateValue. * + * @Deprecated 2.0.0 Use the method getDateValueNoThrow in the DateTimeExcel\Helpers class instead + * * @param mixed $dateValue * * @return mixed Excel date/time serial value, or string if error */ public static function getDateValue($dateValue) { - if (!is_numeric($dateValue)) { - if ((is_object($dateValue)) && ($dateValue instanceof DateTimeInterface)) { - $dateValue = Date::PHPToExcel($dateValue); - } else { - $saveReturnDateType = Functions::getReturnDateType(); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - $dateValue = self::DATEVALUE($dateValue); - Functions::setReturnDateType($saveReturnDateType); - } - } - - return $dateValue; - } - - /** - * getTimeValue. - * - * @param string $timeValue - * - * @return mixed Excel date/time serial value, or string if error - */ - private static function getTimeValue($timeValue) - { - $saveReturnDateType = Functions::getReturnDateType(); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - $timeValue = self::TIMEVALUE($timeValue); - Functions::setReturnDateType($saveReturnDateType); - - return $timeValue; - } - - private static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0) - { - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - $oMonth = (int) $PHPDateObject->format('m'); - $oYear = (int) $PHPDateObject->format('Y'); - - $adjustmentMonthsString = (string) $adjustmentMonths; - if ($adjustmentMonths > 0) { - $adjustmentMonthsString = '+' . $adjustmentMonths; - } - if ($adjustmentMonths != 0) { - $PHPDateObject->modify($adjustmentMonthsString . ' months'); - } - $nMonth = (int) $PHPDateObject->format('m'); - $nYear = (int) $PHPDateObject->format('Y'); - - $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12); - if ($monthDiff != $adjustmentMonths) { - $adjustDays = (int) $PHPDateObject->format('d'); - $adjustDaysString = '-' . $adjustDays . ' days'; - $PHPDateObject->modify($adjustDaysString); - } - - return $PHPDateObject; + return DateTimeExcel\Helpers::getDateValueNoThrow($dateValue); } /** @@ -136,6 +45,8 @@ class DateTime * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way. * + * @Deprecated 2.0.0 Use the funcNow method in the DateTimeExcel\Now class instead + * * Excel Function: * NOW() * @@ -144,10 +55,7 @@ class DateTime */ public static function DATETIMENOW() { - $dti = new DateTimeImmutable(); - $dateArray = date_parse($dti->format('c')); - - return is_array($dateArray) ? self::returnIn3FormatsArray($dateArray) : Functions::VALUE(); + return DateTimeExcel\Now::funcNow(); } /** @@ -161,6 +69,8 @@ class DateTime * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way. * + * @Deprecated 2.0.0 Use the funcToday method in the DateTimeExcel\Today class instead + * * Excel Function: * TODAY() * @@ -169,10 +79,7 @@ class DateTime */ public static function DATENOW() { - $dti = new DateTimeImmutable(); - $dateArray = date_parse($dti->format('c')); - - return is_array($dateArray) ? self::returnIn3FormatsArray($dateArray, true) : Functions::VALUE(); + return DateTimeExcel\Today::funcToday(); } /** @@ -183,6 +90,8 @@ class DateTime * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way. * + * @Deprecated 2.0.0 Use the funcDate method in the DateTimeExcel\Date class instead + * * Excel Function: * DATE(year,month,day) * @@ -226,65 +135,7 @@ class DateTime */ public static function DATE($year = 0, $month = 1, $day = 1) { - $year = Functions::flattenSingleValue($year); - $month = Functions::flattenSingleValue($month); - $day = Functions::flattenSingleValue($day); - - if (($month !== null) && (!is_numeric($month))) { - $month = Date::monthStringToNumber($month); - } - - if (($day !== null) && (!is_numeric($day))) { - $day = Date::dayStringToNumber($day); - } - - $year = ($year !== null) ? StringHelper::testStringAsNumeric($year) : 0; - $month = ($month !== null) ? StringHelper::testStringAsNumeric($month) : 0; - $day = ($day !== null) ? StringHelper::testStringAsNumeric($day) : 0; - if ( - (!is_numeric($year)) || - (!is_numeric($month)) || - (!is_numeric($day)) - ) { - return Functions::VALUE(); - } - $year = (int) $year; - $month = (int) $month; - $day = (int) $day; - - $baseYear = Date::getExcelCalendar(); - // Validate parameters - if ($year < ($baseYear - 1900)) { - return Functions::NAN(); - } - if ((($baseYear - 1900) != 0) && ($year < $baseYear) && ($year >= 1900)) { - return Functions::NAN(); - } - - if (($year < $baseYear) && ($year >= ($baseYear - 1900))) { - $year += 1900; - } - - if ($month < 1) { - // Handle year/month adjustment if month < 1 - --$month; - $year += ceil($month / 12) - 1; - $month = 13 - abs($month % 12); - } elseif ($month > 12) { - // Handle year/month adjustment if month > 12 - $year += floor($month / 12); - $month = ($month % 12); - } - - // Re-validate the year parameter after adjustments - if (($year < $baseYear) || ($year >= 10000)) { - return Functions::NAN(); - } - - // Execute function - $excelDateValue = Date::formattedPHPToExcel($year, $month, $day); - - return self::returnIn3FormatsFloat($excelDateValue); + return DateTimeExcel\Datefunc::funcDate($year, $month, $day); } /** @@ -295,6 +146,8 @@ class DateTime * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way. * + * @Deprecated 2.0.0 Use the funcTime method in the DateTimeExcel\Time class instead + * * Excel Function: * TIME(hour,minute,second) * @@ -315,73 +168,7 @@ class DateTime */ public static function TIME($hour = 0, $minute = 0, $second = 0) { - $hour = Functions::flattenSingleValue($hour); - $minute = Functions::flattenSingleValue($minute); - $second = Functions::flattenSingleValue($second); - - if ($hour == '') { - $hour = 0; - } - if ($minute == '') { - $minute = 0; - } - if ($second == '') { - $second = 0; - } - - if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) { - return Functions::VALUE(); - } - $hour = (int) $hour; - $minute = (int) $minute; - $second = (int) $second; - - if ($second < 0) { - $minute += floor($second / 60); - $second = 60 - abs($second % 60); - if ($second == 60) { - $second = 0; - } - } elseif ($second >= 60) { - $minute += floor($second / 60); - $second = $second % 60; - } - if ($minute < 0) { - $hour += floor($minute / 60); - $minute = 60 - abs($minute % 60); - if ($minute == 60) { - $minute = 0; - } - } elseif ($minute >= 60) { - $hour += floor($minute / 60); - $minute = $minute % 60; - } - - if ($hour > 23) { - $hour = $hour % 24; - } elseif ($hour < 0) { - return Functions::NAN(); - } - - // Execute function - $retType = Functions::getReturnDateType(); - if ($retType === Functions::RETURNDATE_EXCEL) { - $date = 0; - $calendar = Date::getExcelCalendar(); - if ($calendar != Date::CALENDAR_WINDOWS_1900) { - $date = 1; - } - - return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second); - } - if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { - return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600 - } - // RETURNDATE_PHP_DATETIME_OBJECT - // Hour has already been normalized (0-23) above - $phpDateObject = new \DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second); - - return $phpDateObject; + return DateTimeExcel\Time::funcTime($hour, $minute, $second); } /** @@ -394,6 +181,8 @@ class DateTime * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way. * + * @Deprecated 2.0.0 Use the funcDateValue method in the DateTimeExcel\DateValue class instead + * * Excel Function: * DATEVALUE(dateValue) * @@ -411,186 +200,7 @@ class DateTime */ public static function DATEVALUE($dateValue = 1) { - $dti = new DateTimeImmutable(); - $baseYear = Date::getExcelCalendar(); - $dateValue = trim(Functions::flattenSingleValue($dateValue), '"'); - // Strip any ordinals because they're allowed in Excel (English only) - $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue); - // Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany) - $dateValue = str_replace(['/', '.', '-', ' '], ' ', $dateValue); - - $yearFound = false; - $t1 = explode(' ', $dateValue); - $t = ''; - foreach ($t1 as &$t) { - if ((is_numeric($t)) && ($t > 31)) { - if ($yearFound) { - return Functions::VALUE(); - } - if ($t < 100) { - $t += 1900; - } - $yearFound = true; - } - } - if (count($t1) === 1) { - // We've been fed a time value without any date - return ((strpos($t, ':') === false)) ? Functions::Value() : 0.0; - } - if (count($t1) == 2) { - // We only have two parts of the date: either day/month or month/year - if ($yearFound) { - array_unshift($t1, 1); - } else { - if (is_numeric($t1[1]) && $t1[1] > 29) { - $t1[1] += 1900; - array_unshift($t1, 1); - } else { - $t1[] = $dti->format('Y'); - } - } - } - unset($t); - $dateValue = implode(' ', $t1); - - $PHPDateArray = date_parse($dateValue); - if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { - // If original count was 1, we've already returned. - // If it was 2, we added another. - // Therefore, neither of the first 2 stroks below can fail. - $testVal1 = strtok($dateValue, '- '); - $testVal2 = strtok('- '); - $testVal3 = strtok('- ') ?: $dti->format('Y'); - self::adjustYear($testVal1, $testVal2, $testVal3); - $PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3); - if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { - $PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3); - if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { - return Functions::VALUE(); - } - } - } - - $retValue = Functions::Value(); - if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { - // Execute function - self::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y')); - if ($PHPDateArray['year'] < $baseYear) { - return Functions::VALUE(); - } - self::replaceIfEmpty($PHPDateArray['month'], $dti->format('m')); - self::replaceIfEmpty($PHPDateArray['day'], $dti->format('d')); - $PHPDateArray['hour'] = 0; - $PHPDateArray['minute'] = 0; - $PHPDateArray['second'] = 0; - $month = (int) $PHPDateArray['month']; - $day = (int) $PHPDateArray['day']; - $year = (int) $PHPDateArray['year']; - if (!checkdate($month, $day, $year)) { - return ($year === 1900 && $month === 2 && $day === 29) ? self::returnIn3FormatsFloat(60.0) : Functions::VALUE(); - } - $retValue = is_array($PHPDateArray) ? self::returnIn3FormatsArray($PHPDateArray, true) : Functions::VALUE(); - } - - return $retValue; - } - - /** - * Help reduce perceived complexity of some tests. - * - * @param mixed $value - * @param mixed $altValue - */ - private static function replaceIfEmpty(&$value, $altValue): void - { - $value = $value ?: $altValue; - } - - /** - * Adjust year in ambiguous situations. - */ - private static function adjustYear(string $testVal1, string $testVal2, string &$testVal3): void - { - if (!is_numeric($testVal1) || $testVal1 < 31) { - if (!is_numeric($testVal2) || $testVal2 < 12) { - if (is_numeric($testVal3) && $testVal3 < 12) { - $testVal3 += 2000; - } - } - } - } - - /** - * Return result in one of three formats. - * - * @return mixed - */ - private static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false) - { - $retType = Functions::getReturnDateType(); - if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { - return new \DateTime( - $dateArray['year'] - . '-' . $dateArray['month'] - . '-' . $dateArray['day'] - . ' ' . $dateArray['hour'] - . ':' . $dateArray['minute'] - . ':' . $dateArray['second'] - ); - } - $excelDateValue = - Date::formattedPHPToExcel( - $dateArray['year'], - $dateArray['month'], - $dateArray['day'], - $dateArray['hour'], - $dateArray['minute'], - $dateArray['second'] - ); - if ($retType === Functions::RETURNDATE_EXCEL) { - return $noFrac ? floor($excelDateValue) : (float) $excelDateValue; - } - // RETURNDATE_UNIX_TIMESTAMP) - - return (int) Date::excelToTimestamp($excelDateValue); - } - - /** - * Return result in one of three formats. - * - * @return mixed - */ - private static function returnIn3FormatsFloat(float $excelDateValue) - { - $retType = Functions::getReturnDateType(); - if ($retType === Functions::RETURNDATE_EXCEL) { - return $excelDateValue; - } - if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { - return (int) Date::excelToTimestamp($excelDateValue); - } - // RETURNDATE_PHP_DATETIME_OBJECT - - return Date::excelToDateTimeObject($excelDateValue); - } - - /** - * Return result in one of three formats. - * - * @return mixed - */ - private static function returnIn3FormatsObject(\DateTime $PHPDateObject) - { - $retType = Functions::getReturnDateType(); - if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { - return $PHPDateObject; - } - if ($retType === Functions::RETURNDATE_EXCEL) { - return (float) Date::PHPToExcel($PHPDateObject); - } - // RETURNDATE_UNIX_TIMESTAMP - - return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject)); + return DateTimeExcel\DateValue::funcDateValue($dateValue); } /** @@ -603,6 +213,8 @@ class DateTime * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way. * + * @Deprecated 2.0.0 Use the funcTimeValue method in the DateTimeExcel\TimeValue class instead + * * Excel Function: * TIMEVALUE(timeValue) * @@ -616,37 +228,14 @@ class DateTime */ public static function TIMEVALUE($timeValue) { - $timeValue = trim(Functions::flattenSingleValue($timeValue), '"'); - $timeValue = str_replace(['/', '.'], '-', $timeValue); - - $arraySplit = preg_split('/[\/:\-\s]/', $timeValue); - if ((count($arraySplit) == 2 || count($arraySplit) == 3) && $arraySplit[0] > 24) { - $arraySplit[0] = ($arraySplit[0] % 24); - $timeValue = implode(':', $arraySplit); - } - - $PHPDateArray = date_parse($timeValue); - $retValue = Functions::VALUE(); - if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { - // OpenOffice-specific code removed - it works just like Excel - $excelDateValue = Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1; - - $retType = Functions::getReturnDateType(); - if ($retType === Functions::RETURNDATE_EXCEL) { - $retValue = (float) $excelDateValue; - } elseif ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { - $retValue = (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600; - } else { - $retValue = new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']); - } - } - - return $retValue; + return DateTimeExcel\TimeValue::funcTimeValue($timeValue); } /** * DATEDIF. * + * @Deprecated 2.0.0 Use the funcDateDif method in the DateTimeExcel\DateDif class instead + * * @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object * or a standard date string * @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object @@ -657,95 +246,7 @@ class DateTime */ public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D') { - $startDate = Functions::flattenSingleValue($startDate); - $endDate = Functions::flattenSingleValue($endDate); - $unit = strtoupper(Functions::flattenSingleValue($unit)); - - if (is_string($startDate = self::getDateValue($startDate))) { - return Functions::VALUE(); - } - if (is_string($endDate = self::getDateValue($endDate))) { - return Functions::VALUE(); - } - - // Validate parameters - if ($startDate > $endDate) { - return Functions::NAN(); - } - - // Execute function - $difference = $endDate - $startDate; - - $PHPStartDateObject = Date::excelToDateTimeObject($startDate); - $startDays = $PHPStartDateObject->format('j'); - $startMonths = $PHPStartDateObject->format('n'); - $startYears = $PHPStartDateObject->format('Y'); - - $PHPEndDateObject = Date::excelToDateTimeObject($endDate); - $endDays = $PHPEndDateObject->format('j'); - $endMonths = $PHPEndDateObject->format('n'); - $endYears = $PHPEndDateObject->format('Y'); - - $PHPDiffDateObject = $PHPEndDateObject->diff($PHPStartDateObject); - - switch ($unit) { - case 'D': - $retVal = (int) $difference; - - break; - case 'M': - $retVal = (int) 12 * $PHPDiffDateObject->format('%y') + $PHPDiffDateObject->format('%m'); - - break; - case 'Y': - $retVal = (int) $PHPDiffDateObject->format('%y'); - - break; - case 'MD': - if ($endDays < $startDays) { - $retVal = $endDays; - $PHPEndDateObject->modify('-' . $endDays . ' days'); - $adjustDays = $PHPEndDateObject->format('j'); - $retVal += ($adjustDays - $startDays); - } else { - $retVal = (int) $PHPDiffDateObject->format('%d'); - } - - break; - case 'YM': - $retVal = (int) $PHPDiffDateObject->format('%m'); - - break; - case 'YD': - $retVal = (int) $difference; - if ($endYears > $startYears) { - $isLeapStartYear = $PHPStartDateObject->format('L'); - $wasLeapEndYear = $PHPEndDateObject->format('L'); - - // Adjust end year to be as close as possible as start year - while ($PHPEndDateObject >= $PHPStartDateObject) { - $PHPEndDateObject->modify('-1 year'); - $endYears = $PHPEndDateObject->format('Y'); - } - $PHPEndDateObject->modify('+1 year'); - - // Get the result - $retVal = $PHPEndDateObject->diff($PHPStartDateObject)->days; - - // Adjust for leap years cases - $isLeapEndYear = $PHPEndDateObject->format('L'); - $limit = new \DateTime($PHPEndDateObject->format('Y-02-29')); - if (!$isLeapStartYear && !$wasLeapEndYear && $isLeapEndYear && $PHPEndDateObject >= $limit) { - --$retVal; - } - } - - break; - default: - $retVal = Functions::VALUE(); - } - - return $retVal; + return DateTimeExcel\DateDif::funcDateDif($startDate, $endDate, $unit); } /** @@ -753,43 +254,21 @@ class DateTime * * Returns the number of days between two dates * + * @Deprecated 2.0.0 Use the funcDays method in the DateTimeExcel\Days class instead + * * Excel Function: * DAYS(endDate, startDate) * - * @param DateTimeImmutable|float|int|string $endDate Excel date serial value (float), + * @param DateTimeInterface|float|int|string $endDate Excel date serial value (float), * PHP date timestamp (integer), PHP DateTime object, or a standard date string - * @param DateTimeImmutable|float|int|string $startDate Excel date serial value (float), + * @param DateTimeInterface|float|int|string $startDate Excel date serial value (float), * PHP date timestamp (integer), PHP DateTime object, or a standard date string * * @return int|string Number of days between start date and end date or an error */ public static function DAYS($endDate = 0, $startDate = 0) { - $startDate = Functions::flattenSingleValue($startDate); - $endDate = Functions::flattenSingleValue($endDate); - - $startDate = self::getDateValue($startDate); - if (is_string($startDate)) { - return Functions::VALUE(); - } - - $endDate = self::getDateValue($endDate); - if (is_string($endDate)) { - return Functions::VALUE(); - } - - // Execute function - $PHPStartDateObject = Date::excelToDateTimeObject($startDate); - $PHPEndDateObject = Date::excelToDateTimeObject($endDate); - - $diff = $PHPStartDateObject->diff($PHPEndDateObject); - $days = $diff->days; - - if ($diff->invert) { - $days = -$days; - } - - return $days; + return DateTimeExcel\Days::funcDays($endDate, $startDate); } /** @@ -799,6 +278,8 @@ class DateTime * which is used in some accounting calculations. Use this function to help compute payments if * your accounting system is based on twelve 30-day months. * + * @Deprecated 2.0.0 Use the funcDays360 method in the DateTimeExcel\Days360 class instead + * * Excel Function: * DAYS360(startDate,endDate[,method]) * @@ -822,32 +303,7 @@ class DateTime */ public static function DAYS360($startDate = 0, $endDate = 0, $method = false) { - $startDate = Functions::flattenSingleValue($startDate); - $endDate = Functions::flattenSingleValue($endDate); - - if (is_string($startDate = self::getDateValue($startDate))) { - return Functions::VALUE(); - } - if (is_string($endDate = self::getDateValue($endDate))) { - return Functions::VALUE(); - } - - if (!is_bool($method)) { - return Functions::VALUE(); - } - - // Execute function - $PHPStartDateObject = Date::excelToDateTimeObject($startDate); - $startDay = $PHPStartDateObject->format('j'); - $startMonth = $PHPStartDateObject->format('n'); - $startYear = $PHPStartDateObject->format('Y'); - - $PHPEndDateObject = Date::excelToDateTimeObject($endDate); - $endDay = $PHPEndDateObject->format('j'); - $endMonth = $PHPEndDateObject->format('n'); - $endYear = $PHPEndDateObject->format('Y'); - - return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method); + return DateTimeExcel\Days360::funcDays360($startDate, $endDate, $method); } /** @@ -858,6 +314,8 @@ class DateTime * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or * obligations to assign to a specific term. * + * @Deprecated 2.0.0 Use the funcYearFrac method in the DateTimeExcel\YearFrac class instead + * * Excel Function: * YEARFRAC(startDate,endDate[,method]) * See https://lists.oasis-open.org/archives/office-formula/200806/msg00039.html @@ -878,78 +336,7 @@ class DateTime */ public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0) { - $startDate = Functions::flattenSingleValue($startDate); - $endDate = Functions::flattenSingleValue($endDate); - $method = Functions::flattenSingleValue($method); - - if (is_string($startDate = self::getDateValue($startDate))) { - return Functions::VALUE(); - } - if (is_string($endDate = self::getDateValue($endDate))) { - return Functions::VALUE(); - } - if ($startDate > $endDate) { - $temp = $startDate; - $startDate = $endDate; - $endDate = $temp; - } - - if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) { - switch ($method) { - case 0: - return self::DAYS360($startDate, $endDate) / 360; - case 1: - $days = self::DATEDIF($startDate, $endDate); - $startYear = self::YEAR($startDate); - $endYear = self::YEAR($endDate); - $years = $endYear - $startYear + 1; - $startMonth = self::MONTHOFYEAR($startDate); - $startDay = self::DAYOFMONTH($startDate); - $endMonth = self::MONTHOFYEAR($endDate); - $endDay = self::DAYOFMONTH($endDate); - $startMonthDay = 100 * $startMonth + $startDay; - $endMonthDay = 100 * $endMonth + $endDay; - if ($years == 1) { - if (self::isLeapYear($endYear)) { - $tmpCalcAnnualBasis = 366; - } else { - $tmpCalcAnnualBasis = 365; - } - } elseif ($years == 2 && $startMonthDay >= $endMonthDay) { - if (self::isLeapYear($startYear)) { - if ($startMonthDay <= 229) { - $tmpCalcAnnualBasis = 366; - } else { - $tmpCalcAnnualBasis = 365; - } - } elseif (self::isLeapYear($endYear)) { - if ($endMonthDay >= 229) { - $tmpCalcAnnualBasis = 366; - } else { - $tmpCalcAnnualBasis = 365; - } - } else { - $tmpCalcAnnualBasis = 365; - } - } else { - $tmpCalcAnnualBasis = 0; - for ($year = $startYear; $year <= $endYear; ++$year) { - $tmpCalcAnnualBasis += self::isLeapYear($year) ? 366 : 365; - } - $tmpCalcAnnualBasis /= $years; - } - - return $days / $tmpCalcAnnualBasis; - case 2: - return self::DATEDIF($startDate, $endDate) / 360; - case 3: - return self::DATEDIF($startDate, $endDate) / 365; - case 4: - return self::DAYS360($startDate, $endDate, true) / 360; - } - } - - return Functions::VALUE(); + return DateTimeExcel\YearFrac::funcYearFrac($startDate, $endDate, $method); } /** @@ -960,6 +347,8 @@ class DateTime * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days * worked during a specific term. * + * @Deprecated 2.0.0 Use the funcNetworkDays method in the DateTimeExcel\NetworkDays class instead + * * Excel Function: * NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]]) * @@ -972,62 +361,7 @@ class DateTime */ public static function NETWORKDAYS($startDate, $endDate, ...$dateArgs) { - // Retrieve the mandatory start and end date that are referenced in the function definition - $startDate = Functions::flattenSingleValue($startDate); - $endDate = Functions::flattenSingleValue($endDate); - // Get the optional days - $dateArgs = Functions::flattenArray($dateArgs); - - // Validate the start and end dates - if (is_string($startDate = $sDate = self::getDateValue($startDate))) { - return Functions::VALUE(); - } - $startDate = (float) floor($startDate); - if (is_string($endDate = $eDate = self::getDateValue($endDate))) { - return Functions::VALUE(); - } - $endDate = (float) floor($endDate); - - if ($sDate > $eDate) { - $startDate = $eDate; - $endDate = $sDate; - } - - // Execute function - $startDoW = 6 - self::WEEKDAY($startDate, 2); - if ($startDoW < 0) { - $startDoW = 5; - } - $endDoW = self::WEEKDAY($endDate, 2); - if ($endDoW >= 6) { - $endDoW = 0; - } - - $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5; - $partWeekDays = $endDoW + $startDoW; - if ($partWeekDays > 5) { - $partWeekDays -= 5; - } - - // Test any extra holiday parameters - $holidayCountedArray = []; - foreach ($dateArgs as $holidayDate) { - if (is_string($holidayDate = self::getDateValue($holidayDate))) { - return Functions::VALUE(); - } - if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { - if ((self::WEEKDAY($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) { - --$partWeekDays; - $holidayCountedArray[] = $holidayDate; - } - } - } - - if ($sDate > $eDate) { - return 0 - ($wholeWeekDays + $partWeekDays); - } - - return $wholeWeekDays + $partWeekDays; + return DateTimeExcel\NetworkDays::funcNetworkDays($startDate, $endDate, ...$dateArgs); } /** @@ -1038,6 +372,8 @@ class DateTime * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected * delivery times, or the number of days of work performed. * + * @Deprecated 2.0.0 Use the funcWorkDay method in the DateTimeExcel\WorkDay class instead + * * Excel Function: * WORKDAY(startDate,endDays[,holidays[,holiday[,...]]]) * @@ -1052,84 +388,7 @@ class DateTime */ public static function WORKDAY($startDate, $endDays, ...$dateArgs) { - // Retrieve the mandatory start date and days that are referenced in the function definition - $startDate = Functions::flattenSingleValue($startDate); - $endDays = Functions::flattenSingleValue($endDays); - // Get the optional days - $dateArgs = Functions::flattenArray($dateArgs); - - if ((is_string($startDate = self::getDateValue($startDate))) || (!is_numeric($endDays))) { - return Functions::VALUE(); - } - $startDate = (float) floor($startDate); - $endDays = (int) floor($endDays); - // If endDays is 0, we always return startDate - if ($endDays == 0) { - return $startDate; - } - - $decrementing = $endDays < 0; - - // Adjust the start date if it falls over a weekend - - $startDoW = self::WEEKDAY($startDate, 3); - if (self::WEEKDAY($startDate, 3) >= 5) { - $startDate += ($decrementing) ? -$startDoW + 4 : 7 - $startDoW; - ($decrementing) ? $endDays++ : $endDays--; - } - - // Add endDays - $endDate = (float) $startDate + ((int) ($endDays / 5) * 7) + ($endDays % 5); - - // Adjust the calculated end date if it falls over a weekend - $endDoW = self::WEEKDAY($endDate, 3); - if ($endDoW >= 5) { - $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW; - } - - // Test any extra holiday parameters - if (!empty($dateArgs)) { - $holidayCountedArray = $holidayDates = []; - foreach ($dateArgs as $holidayDate) { - if (($holidayDate !== null) && (trim($holidayDate) > '')) { - if (is_string($holidayDate = self::getDateValue($holidayDate))) { - return Functions::VALUE(); - } - if (self::WEEKDAY($holidayDate, 3) < 5) { - $holidayDates[] = $holidayDate; - } - } - } - if ($decrementing) { - rsort($holidayDates, SORT_NUMERIC); - } else { - sort($holidayDates, SORT_NUMERIC); - } - foreach ($holidayDates as $holidayDate) { - if ($decrementing) { - if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) { - if (!in_array($holidayDate, $holidayCountedArray)) { - --$endDate; - $holidayCountedArray[] = $holidayDate; - } - } - } else { - if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { - if (!in_array($holidayDate, $holidayCountedArray)) { - ++$endDate; - $holidayCountedArray[] = $holidayDate; - } - } - } - // Adjust the calculated end date if it falls over a weekend - $endDoW = self::WEEKDAY($endDate, 3); - if ($endDoW >= 5) { - $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW; - } - } - } - - return self::returnIn3FormatsFloat($endDate); + return DateTimeExcel\WorkDay::funcWorkDay($startDate, $endDays, ...$dateArgs); } /** @@ -1138,6 +397,8 @@ class DateTime * Returns the day of the month, for a specified date. The day is given as an integer * ranging from 1 to 31. * + * @Deprecated 2.0.0 Use the funcDay method in the DateTimeExcel\Day class instead + * * Excel Function: * DAY(dateValue) * @@ -1148,27 +409,7 @@ class DateTime */ public static function DAYOFMONTH($dateValue = 1) { - $dateValue = Functions::flattenSingleValue($dateValue); - - if ($dateValue === null || is_bool($dateValue)) { - return (int) $dateValue; - } - if (is_string($dateValue = self::getDateValue($dateValue))) { - return Functions::VALUE(); - } - - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) { - if ($dateValue < 0.0) { - return Functions::NAN(); - } elseif ($dateValue < 1.0) { - return 0; - } - } - - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - - return (int) $PHPDateObject->format('j'); + return DateTimeExcel\Day::funcDay($dateValue); } /** @@ -1177,6 +418,8 @@ class DateTime * Returns the day of the week for a specified date. The day is given as an integer * ranging from 0 to 7 (dependent on the requested style). * + * @Deprecated 2.0.0 Use the funcWeekDay method in the DateTimeExcel\WeekDay class instead + * * Excel Function: * WEEKDAY(dateValue[,style]) * @@ -1191,70 +434,169 @@ class DateTime */ public static function WEEKDAY($dateValue = 1, $style = 1) { - $dateValue = Functions::flattenSingleValue($dateValue); - self::nullFalseTrueToNumber($dateValue); - $style = Functions::flattenSingleValue($style); - - if (!is_numeric($style)) { - return Functions::VALUE(); - } elseif (($style < 1) || ($style > 3)) { - return Functions::NAN(); - } - $style = floor($style); - - $dateValue = self::getDateValue($dateValue); - if (is_string($dateValue)) { - return Functions::VALUE(); - } - if ($dateValue < 0.0) { - return Functions::NAN(); - } - - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - self::silly1900($PHPDateObject); - $DoW = (int) $PHPDateObject->format('w'); - - switch ($style) { - case 1: - ++$DoW; - - break; - case 2: - if ($DoW === 0) { - $DoW = 7; - } - - break; - case 3: - if ($DoW === 0) { - $DoW = 7; - } - --$DoW; - - break; - } - - return $DoW; + return DateTimeExcel\WeekDay::funcWeekDay($dateValue, $style); } + /** + * STARTWEEK_SUNDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_SUNDAY instead + */ const STARTWEEK_SUNDAY = 1; + + /** + * STARTWEEK_MONDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_MONDAY instead + */ const STARTWEEK_MONDAY = 2; + + /** + * STARTWEEK_MONDAY_ALT. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_MONDAY_ALT instead + */ const STARTWEEK_MONDAY_ALT = 11; + + /** + * STARTWEEK_TUESDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_TUESDAY instead + */ const STARTWEEK_TUESDAY = 12; + + /** + * STARTWEEK_WEDNESDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_WEDNESDAY instead + */ const STARTWEEK_WEDNESDAY = 13; + + /** + * STARTWEEK_THURSDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_THURSDAY instead + */ const STARTWEEK_THURSDAY = 14; + + /** + * STARTWEEK_FRIDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_FRIDAY instead + */ const STARTWEEK_FRIDAY = 15; + + /** + * STARTWEEK_SATURDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_SATURDAY instead + */ const STARTWEEK_SATURDAY = 16; + + /** + * STARTWEEK_SUNDAY_ALT. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_SUNDAY_ALT instead + */ const STARTWEEK_SUNDAY_ALT = 17; + + /** + * DOW_SUNDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_SUNDAY instead + */ const DOW_SUNDAY = 1; + + /** + * DOW_MONDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_MONDAY instead + */ const DOW_MONDAY = 2; + + /** + * DOW_TUESDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_TUESDAY instead + */ const DOW_TUESDAY = 3; + + /** + * DOW_WEDNESDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_WEDNESDAY instead + */ const DOW_WEDNESDAY = 4; + + /** + * DOW_THURSDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_THURSDAY instead + */ const DOW_THURSDAY = 5; + + /** + * DOW_FRIDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_FRIDAY instead + */ const DOW_FRIDAY = 6; + + /** + * DOW_SATURDAY. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\DOW_SATURDAY instead + */ const DOW_SATURDAY = 7; + + /** + * STARTWEEK_MONDAY_ISO. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\STARTWEEK_MONDAY_ISO instead + */ const STARTWEEK_MONDAY_ISO = 21; + + /** + * METHODARR. + * + * @Deprecated 2.0.0 + * + * @see Use DateTimeExcel\Constants\METHODARR instead + */ const METHODARR = [ self::STARTWEEK_SUNDAY => self::DOW_SUNDAY, self::DOW_MONDAY, @@ -1278,6 +620,8 @@ class DateTime * three days or less in the first week of January, the WEEKNUM function returns week numbers * that are incorrect according to the European standard. * + * @Deprecated 2.0.0 Use the funcWeekNum method in the DateTimeExcel\WeekNum class instead + * * Excel Function: * WEEKNUM(dateValue[,style]) * @@ -1299,67 +643,7 @@ class DateTime */ public static function WEEKNUM($dateValue = 1, $method = self::STARTWEEK_SUNDAY) { - $origDateValueNull = $dateValue === null; - $dateValue = Functions::flattenSingleValue($dateValue); - $method = Functions::flattenSingleValue($method); - if (!is_numeric($method)) { - return Functions::VALUE(); - } - - $method = (int) $method; - if (!array_key_exists($method, self::METHODARR)) { - return Functions::NaN(); - } - $method = self::METHODARR[$method]; - if ($dateValue === null) { // boolean not allowed - // This seems to be an additional Excel bug. - if (self::buggyWeekNum1900($method)) { - return 0; - } - //$dateValue = 1; - $dateValue = (Date::getExcelCalendar() === DATE::CALENDAR_MAC_1904) ? 0 : 1; - } - - $dateValue = self::getDateValue($dateValue); - if (is_string($dateValue)) { - return Functions::VALUE(); - } - if ($dateValue < 0.0) { - return Functions::NAN(); - } - - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - if ($method == self::STARTWEEK_MONDAY_ISO) { - self::silly1900($PHPDateObject); - - return (int) $PHPDateObject->format('W'); - } - if (self::buggyWeekNum1904($method, $origDateValueNull, $PHPDateObject)) { - return 0; - } - self::silly1900($PHPDateObject, '+ 5 years'); // 1905 calendar matches - $dayOfYear = $PHPDateObject->format('z'); - $PHPDateObject->modify('-' . $dayOfYear . ' days'); - $firstDayOfFirstWeek = $PHPDateObject->format('w'); - $daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7; - $daysInFirstWeek += 7 * !$daysInFirstWeek; - $endFirstWeek = $daysInFirstWeek - 1; - $weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7); - - return (int) $weekOfYear; - } - - private static function buggyWeekNum1900(int $method): bool - { - return $method === self::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_WINDOWS_1900; - } - - private static function buggyWeekNum1904(int $method, bool $origNull, \DateTime $dateObject): bool - { - // This appears to be another Excel bug. - - return $method === self::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_MAC_1904 && !$origNull && $dateObject->format('Y-m-d') === '1904-01-01'; + return DateTimeExcel\WeekNum::funcWeekNum($dateValue, $method); } /** @@ -1367,6 +651,8 @@ class DateTime * * Returns the ISO 8601 week number of the year for a specified date. * + * @Deprecated 2.0.0 Use the funcIsoWeeknum method in the DateTimeExcel\Isoweeknum class instead + * * Excel Function: * ISOWEEKNUM(dateValue) * @@ -1377,22 +663,7 @@ class DateTime */ public static function ISOWEEKNUM($dateValue = 1) { - $dateValue = Functions::flattenSingleValue($dateValue); - self::nullFalseTrueToNumber($dateValue); - - $dateValue = self::getDateValue($dateValue); - if (!is_numeric($dateValue)) { - return Functions::VALUE(); - } - if ($dateValue < 0.0) { - return Functions::NAN(); - } - - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - self::silly1900($PHPDateObject); - - return (int) $PHPDateObject->format('W'); + return DateTimeExcel\IsoweekNum::funcIsoWeekNum($dateValue); } /** @@ -1401,6 +672,8 @@ class DateTime * Returns the month of a date represented by a serial number. * The month is given as an integer, ranging from 1 (January) to 12 (December). * + * @Deprecated 2.0.0 Use the funcMonth method in the DateTimeExcel\Month class instead + * * Excel Function: * MONTH(dateValue) * @@ -1411,21 +684,7 @@ class DateTime */ public static function MONTHOFYEAR($dateValue = 1) { - $dateValue = Functions::flattenSingleValue($dateValue); - - if (empty($dateValue)) { - $dateValue = 1; - } - if (is_string($dateValue = self::getDateValue($dateValue))) { - return Functions::VALUE(); - } elseif ($dateValue < 0.0) { - return Functions::NAN(); - } - - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - - return (int) $PHPDateObject->format('n'); + return DateTimeExcel\Month::funcMonth($dateValue); } /** @@ -1434,6 +693,8 @@ class DateTime * Returns the year corresponding to a date. * The year is returned as an integer in the range 1900-9999. * + * @Deprecated 2.0.0 Use the funcYear method in the DateTimeExcel\Year class instead + * * Excel Function: * YEAR(dateValue) * @@ -1444,20 +705,7 @@ class DateTime */ public static function YEAR($dateValue = 1) { - $dateValue = Functions::flattenSingleValue($dateValue); - - if ($dateValue === null) { - $dateValue = 1; - } elseif (is_string($dateValue = self::getDateValue($dateValue))) { - return Functions::VALUE(); - } elseif ($dateValue < 0.0) { - return Functions::NAN(); - } - - // Execute function - $PHPDateObject = Date::excelToDateTimeObject($dateValue); - - return (int) $PHPDateObject->format('Y'); + return DateTimeExcel\Year::funcYear($dateValue); } /** @@ -1466,6 +714,8 @@ class DateTime * Returns the hour of a time value. * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.). * + * @Deprecated 2.0.0 Use the funcHour method in the DateTimeExcel\Hour class instead + * * Excel Function: * HOUR(timeValue) * @@ -1476,24 +726,7 @@ class DateTime */ public static function HOUROFDAY($timeValue = 0) { - $timeValue = Functions::flattenSingleValue($timeValue); - - if (!is_numeric($timeValue)) { - // Gnumeric test removed - it operates like Excel - $timeValue = self::getTimeValue($timeValue); - if (is_string($timeValue)) { - return Functions::VALUE(); - } - } - // Execute function - if ($timeValue >= 1) { - $timeValue = fmod($timeValue, 1); - } elseif ($timeValue < 0.0) { - return Functions::NAN(); - } - $timeValue = Date::excelToTimestamp($timeValue); - - return (int) gmdate('G', $timeValue); + return DateTimeExcel\Hour::funcHour($timeValue); } /** @@ -1502,6 +735,8 @@ class DateTime * Returns the minutes of a time value. * The minute is given as an integer, ranging from 0 to 59. * + * @Deprecated 2.0.0 Use the funcMinute method in the DateTimeExcel\Minute class instead + * * Excel Function: * MINUTE(timeValue) * @@ -1512,24 +747,7 @@ class DateTime */ public static function MINUTE($timeValue = 0) { - $timeValue = $timeTester = Functions::flattenSingleValue($timeValue); - - if (!is_numeric($timeValue)) { - // Gnumeric test removed - it operates like Excel - $timeValue = self::getTimeValue($timeValue); - if (is_string($timeValue)) { - return Functions::VALUE(); - } - } - // Execute function - if ($timeValue >= 1) { - $timeValue = fmod($timeValue, 1); - } elseif ($timeValue < 0.0) { - return Functions::NAN(); - } - $timeValue = Date::excelToTimestamp($timeValue); - - return (int) gmdate('i', $timeValue); + return DateTimeExcel\Minute::funcMinute($timeValue); } /** @@ -1538,6 +756,8 @@ class DateTime * Returns the seconds of a time value. * The second is given as an integer in the range 0 (zero) to 59. * + * @Deprecated 2.0.0 Use the funcSecond method in the DateTimeExcel\Second class instead + * * Excel Function: * SECOND(timeValue) * @@ -1548,24 +768,7 @@ class DateTime */ public static function SECOND($timeValue = 0) { - $timeValue = Functions::flattenSingleValue($timeValue); - - if (!is_numeric($timeValue)) { - // Gnumeric test removed - it operates like Excel - $timeValue = self::getTimeValue($timeValue); - if (is_string($timeValue)) { - return Functions::VALUE(); - } - } - // Execute function - if ($timeValue >= 1) { - $timeValue = fmod($timeValue, 1); - } elseif ($timeValue < 0.0) { - return Functions::NAN(); - } - $timeValue = Date::excelToTimestamp($timeValue); - - return (int) gmdate('s', $timeValue); + return DateTimeExcel\Second::funcSecond($timeValue); } /** @@ -1576,6 +779,8 @@ class DateTime * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month * as the date of issue. * + * @Deprecated 2.0.0 Use the funcEDate method in the DateTimeExcel\EDate class instead + * * Excel Function: * EDATE(dateValue,adjustmentMonths) * @@ -1590,22 +795,7 @@ class DateTime */ public static function EDATE($dateValue = 1, $adjustmentMonths = 0) { - $dateValue = Functions::flattenSingleValue($dateValue); - $adjustmentMonths = Functions::flattenSingleValue($adjustmentMonths); - - if (!is_numeric($adjustmentMonths)) { - return Functions::VALUE(); - } - $adjustmentMonths = floor($adjustmentMonths); - - if (is_string($dateValue = self::getDateValue($dateValue))) { - return Functions::VALUE(); - } - - // Execute function - $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths); - - return self::returnIn3FormatsObject($PHPDateObject); + return DateTimeExcel\EDate::funcEDate($dateValue, $adjustmentMonths); } /** @@ -1615,6 +805,8 @@ class DateTime * before or after start_date. * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month. * + * @Deprecated 2.0.0 Use the funcEoMonth method in the DateTimeExcel\EoMonth class instead + * * Excel Function: * EOMONTH(dateValue,adjustmentMonths) * @@ -1629,49 +821,6 @@ class DateTime */ public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0) { - $dateValue = Functions::flattenSingleValue($dateValue); - $adjustmentMonths = Functions::flattenSingleValue($adjustmentMonths); - - if (!is_numeric($adjustmentMonths)) { - return Functions::VALUE(); - } - $adjustmentMonths = floor($adjustmentMonths); - - if (is_string($dateValue = self::getDateValue($dateValue))) { - return Functions::VALUE(); - } - - // Execute function - $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths + 1); - $adjustDays = (int) $PHPDateObject->format('d'); - $adjustDaysString = '-' . $adjustDays . ' days'; - $PHPDateObject->modify($adjustDaysString); - - return self::returnIn3FormatsObject($PHPDateObject); - } - - /** - * Many functions accept null/false/true argument treated as 0/0/1. - * - * @param mixed $number - */ - private static function nullFalseTrueToNumber(&$number): void - { - $number = Functions::flattenSingleValue($number); - $baseYear = Date::getExcelCalendar(); - $nullVal = $baseYear === DATE::CALENDAR_MAC_1904 ? 0 : 1; - if ($number === null) { - $number = $nullVal; - } elseif (is_bool($number)) { - $number = $nullVal + (int) $number; - } - } - - private static function silly1900(\DateTime $PHPDateObject, string $mod = '-1 day'): void - { - $isoDate = $PHPDateObject->format('c'); - if ($isoDate < '1900-03-01') { - $PHPDateObject->modify($mod); - } + return DateTimeExcel\EoMonth::funcEoMonth($dateValue, $adjustmentMonths); } } diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Constants.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Constants.php new file mode 100644 index 00000000..da1b81c1 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Constants.php @@ -0,0 +1,37 @@ + self::DOW_SUNDAY, + self::DOW_MONDAY, + self::STARTWEEK_MONDAY_ALT => self::DOW_MONDAY, + self::DOW_TUESDAY, + self::DOW_WEDNESDAY, + self::DOW_THURSDAY, + self::DOW_FRIDAY, + self::DOW_SATURDAY, + self::DOW_SUNDAY, + self::STARTWEEK_MONDAY_ISO => self::STARTWEEK_MONDAY_ISO, + ]; +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php new file mode 100644 index 00000000..ace22cbf --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php @@ -0,0 +1,146 @@ +getMessage(); + } + + // Execute function + $PHPStartDateObject = Date::excelToDateTimeObject($startDate); + $startDays = (int) $PHPStartDateObject->format('j'); + $startMonths = (int) $PHPStartDateObject->format('n'); + $startYears = (int) $PHPStartDateObject->format('Y'); + + $PHPEndDateObject = Date::excelToDateTimeObject($endDate); + $endDays = (int) $PHPEndDateObject->format('j'); + $endMonths = (int) $PHPEndDateObject->format('n'); + $endYears = (int) $PHPEndDateObject->format('Y'); + + $PHPDiffDateObject = $PHPEndDateObject->diff($PHPStartDateObject); + + $retVal = false; + $retVal = self::replaceRetValue($retVal, $unit, 'D') ?? self::datedifD($difference); + $retVal = self::replaceRetValue($retVal, $unit, 'M') ?? self::datedifM($PHPDiffDateObject); + $retVal = self::replaceRetValue($retVal, $unit, 'MD') ?? self::datedifMD($startDays, $endDays, $PHPEndDateObject, $PHPDiffDateObject); + $retVal = self::replaceRetValue($retVal, $unit, 'Y') ?? self::datedifY($PHPDiffDateObject); + $retVal = self::replaceRetValue($retVal, $unit, 'YD') ?? self::datedifYD($difference, $startYears, $endYears, $PHPStartDateObject, $PHPEndDateObject); + $retVal = self::replaceRetValue($retVal, $unit, 'YM') ?? self::datedifYM($PHPDiffDateObject); + + return is_bool($retVal) ? Functions::VALUE() : $retVal; + } + + private static function initialDiff(float $startDate, float $endDate): float + { + // Validate parameters + if ($startDate > $endDate) { + throw new Exception(Functions::NAN()); + } + + return $endDate - $startDate; + } + + /** + * Decide whether it's time to set retVal. + * + * @param bool|int $retVal + * + * @return null|bool|int + */ + private static function replaceRetValue($retVal, string $unit, string $compare) + { + if ($retVal !== false || $unit !== $compare) { + return $retVal; + } + + return null; + } + + private static function datedifD(float $difference): int + { + return (int) $difference; + } + + private static function datedifM(DateInterval $PHPDiffDateObject): int + { + return (int) 12 * $PHPDiffDateObject->format('%y') + $PHPDiffDateObject->format('%m'); + } + + private static function datedifMD(int $startDays, int $endDays, DateTime $PHPEndDateObject, DateInterval $PHPDiffDateObject): int + { + if ($endDays < $startDays) { + $retVal = $endDays; + $PHPEndDateObject->modify('-' . $endDays . ' days'); + $adjustDays = (int) $PHPEndDateObject->format('j'); + $retVal += ($adjustDays - $startDays); + } else { + $retVal = (int) $PHPDiffDateObject->format('%d'); + } + + return $retVal; + } + + private static function datedifY(DateInterval $PHPDiffDateObject): int + { + return (int) $PHPDiffDateObject->format('%y'); + } + + private static function datedifYD(float $difference, int $startYears, int $endYears, DateTime $PHPStartDateObject, DateTime $PHPEndDateObject): int + { + $retVal = (int) $difference; + if ($endYears > $startYears) { + $isLeapStartYear = $PHPStartDateObject->format('L'); + $wasLeapEndYear = $PHPEndDateObject->format('L'); + + // Adjust end year to be as close as possible as start year + while ($PHPEndDateObject >= $PHPStartDateObject) { + $PHPEndDateObject->modify('-1 year'); + $endYears = $PHPEndDateObject->format('Y'); + } + $PHPEndDateObject->modify('+1 year'); + + // Get the result + $retVal = $PHPEndDateObject->diff($PHPStartDateObject)->days; + + // Adjust for leap years cases + $isLeapEndYear = $PHPEndDateObject->format('L'); + $limit = new DateTime($PHPEndDateObject->format('Y-02-29')); + if (!$isLeapStartYear && !$wasLeapEndYear && $isLeapEndYear && $PHPEndDateObject >= $limit) { + --$retVal; + } + } + + return (int) $retVal; + } + + private static function datedifYM(DateInterval $PHPDiffDateObject): int + { + return (int) $PHPDiffDateObject->format('%m'); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php new file mode 100644 index 00000000..3c15d06a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php @@ -0,0 +1,151 @@ + 31)) { + if ($yearFound) { + return Functions::VALUE(); + } + if ($t < 100) { + $t += 1900; + } + $yearFound = true; + } + } + if (count($t1) === 1) { + // We've been fed a time value without any date + return ((strpos($t, ':') === false)) ? Functions::Value() : 0.0; + } + unset($t); + + $dateValue = self::t1ToString($t1, $dti, $yearFound); + + $PHPDateArray = self::setUpArray($dateValue, $dti); + + return self::finalResults($PHPDateArray, $dti, $baseYear); + } + + private static function t1ToString(array $t1, DateTimeImmutable $dti, bool $yearFound): string + { + if (count($t1) == 2) { + // We only have two parts of the date: either day/month or month/year + if ($yearFound) { + array_unshift($t1, 1); + } else { + if (is_numeric($t1[1]) && $t1[1] > 29) { + $t1[1] += 1900; + array_unshift($t1, 1); + } else { + $t1[] = $dti->format('Y'); + } + } + } + $dateValue = implode(' ', $t1); + + return $dateValue; + } + + /** + * Parse date. + * + * @return array|bool + */ + private static function setUpArray(string $dateValue, DateTimeImmutable $dti) + { + $PHPDateArray = date_parse($dateValue); + if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { + // If original count was 1, we've already returned. + // If it was 2, we added another. + // Therefore, neither of the first 2 stroks below can fail. + $testVal1 = strtok($dateValue, '- '); + $testVal2 = strtok('- '); + $testVal3 = strtok('- ') ?: $dti->format('Y'); + Helpers::adjustYear($testVal1, $testVal2, $testVal3); + $PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3); + if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) { + $PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3); + } + } + + return $PHPDateArray; + } + + /** + * Final results. + * + * @param array|false $PHPDateArray + * + * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, + * depending on the value of the ReturnDateType flag + */ + private static function finalResults($PHPDateArray, DateTimeImmutable $dti, int $baseYear) + { + $retValue = Functions::Value(); + if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { + // Execute function + Helpers::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y')); + if ($PHPDateArray['year'] < $baseYear) { + return Functions::VALUE(); + } + Helpers::replaceIfEmpty($PHPDateArray['month'], $dti->format('m')); + Helpers::replaceIfEmpty($PHPDateArray['day'], $dti->format('d')); + $PHPDateArray['hour'] = 0; + $PHPDateArray['minute'] = 0; + $PHPDateArray['second'] = 0; + $month = (int) $PHPDateArray['month']; + $day = (int) $PHPDateArray['day']; + $year = (int) $PHPDateArray['year']; + if (!checkdate($month, $day, $year)) { + return ($year === 1900 && $month === 2 && $day === 29) ? Helpers::returnIn3FormatsFloat(60.0) : Functions::VALUE(); + } + $retValue = Helpers::returnIn3FormatsArray($PHPDateArray, true); + } + + return $retValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Datefunc.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Datefunc.php new file mode 100644 index 00000000..ec8be2df --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Datefunc.php @@ -0,0 +1,168 @@ +getMessage(); + } + + // Execute function + $excelDateValue = Date::formattedPHPToExcel($year, $month, $day); + + return Helpers::returnIn3FormatsFloat($excelDateValue); + } + + /** + * Convert year from multiple formats to int. + * + * @param mixed $year + */ + private static function getYear($year, int $baseYear): int + { + $year = Functions::flattenSingleValue($year); + $year = ($year !== null) ? StringHelper::testStringAsNumeric($year) : 0; + if (!is_numeric($year)) { + throw new Exception(Functions::VALUE()); + } + $year = (int) $year; + + if ($year < ($baseYear - 1900)) { + throw new Exception(Functions::NAN()); + } + if ((($baseYear - 1900) !== 0) && ($year < $baseYear) && ($year >= 1900)) { + throw new Exception(Functions::NAN()); + } + + if (($year < $baseYear) && ($year >= ($baseYear - 1900))) { + $year += 1900; + } + + return $year; + } + + /** + * Convert month from multiple formats to int. + * + * @param mixed $month + */ + private static function getMonth($month): int + { + $month = Functions::flattenSingleValue($month); + + if (($month !== null) && (!is_numeric($month))) { + $month = Date::monthStringToNumber($month); + } + + $month = ($month !== null) ? StringHelper::testStringAsNumeric($month) : 0; + if (!is_numeric($month)) { + throw new Exception(Functions::VALUE()); + } + + return (int) $month; + } + + /** + * Convert day from multiple formats to int. + * + * @param mixed $day + */ + private static function getDay($day): int + { + $day = Functions::flattenSingleValue($day); + + if (($day !== null) && (!is_numeric($day))) { + $day = Date::dayStringToNumber($day); + } + + $day = ($day !== null) ? StringHelper::testStringAsNumeric($day) : 0; + if (!is_numeric($day)) { + throw new Exception(Functions::VALUE()); + } + + return (int) $day; + } + + private static function adjustYearMonth(int &$year, int &$month, int $baseYear): void + { + if ($month < 1) { + // Handle year/month adjustment if month < 1 + --$month; + $year += ceil($month / 12) - 1; + $month = 13 - abs($month % 12); + } elseif ($month > 12) { + // Handle year/month adjustment if month > 12 + $year += floor($month / 12); + $month = ($month % 12); + } + + // Re-validate the year parameter after adjustments + if (($year < $baseYear) || ($year >= 10000)) { + throw new Exception(Functions::NAN()); + } + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Day.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Day.php new file mode 100644 index 00000000..6ab27184 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Day.php @@ -0,0 +1,61 @@ += 0) { + return $weirdResult; + } + + try { + $dateValue = Helpers::getDateValue($dateValue); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + + return (int) $PHPDateObject->format('j'); + } + + private static function weirdCondition($dateValue): int + { + // Excel does not treat 0 consistently for DAY vs. (MONTH or YEAR) + if (Date::getExcelCalendar() === DATE::CALENDAR_WINDOWS_1900 && Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) { + if (is_bool($dateValue)) { + return (int) $dateValue; + } + if ($dateValue === null) { + return 0; + } + if (is_numeric($dateValue) && $dateValue < 1 && $dateValue >= 0) { + return 0; + } + } + + return -1; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php new file mode 100644 index 00000000..2c814e8e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days.php @@ -0,0 +1,51 @@ +getMessage(); + } + + // Execute function + $PHPStartDateObject = Date::excelToDateTimeObject($startDate); + $PHPEndDateObject = Date::excelToDateTimeObject($endDate); + + $days = Functions::VALUE(); + $diff = $PHPStartDateObject->diff($PHPEndDateObject); + if ($diff !== false && !is_bool($diff->days)) { + $days = $diff->days; + if ($diff->invert) { + $days = -$days; + } + } + + return $days; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php new file mode 100644 index 00000000..068ea2bc --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php @@ -0,0 +1,106 @@ +getMessage(); + } + + if (!is_bool($method)) { + return Functions::VALUE(); + } + + // Execute function + $PHPStartDateObject = Date::excelToDateTimeObject($startDate); + $startDay = $PHPStartDateObject->format('j'); + $startMonth = $PHPStartDateObject->format('n'); + $startYear = $PHPStartDateObject->format('Y'); + + $PHPEndDateObject = Date::excelToDateTimeObject($endDate); + $endDay = $PHPEndDateObject->format('j'); + $endMonth = $PHPEndDateObject->format('n'); + $endYear = $PHPEndDateObject->format('Y'); + + return self::dateDiff360((int) $startDay, (int) $startMonth, (int) $startYear, (int) $endDay, (int) $endMonth, (int) $endYear, !$method); + } + + /** + * Return the number of days between two dates based on a 360 day calendar. + */ + private static function dateDiff360(int $startDay, int $startMonth, int $startYear, int $endDay, int $endMonth, int $endYear, bool $methodUS): int + { + $startDay = self::getStartDay($startDay, $startMonth, $startYear, $methodUS); + $endDay = self::getEndDay($endDay, $endMonth, $endYear, $startDay, $methodUS); + + return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360; + } + + private static function getStartDay(int $startDay, int $startMonth, int $startYear, bool $methodUS): int + { + if ($startDay == 31) { + --$startDay; + } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !Helpers::isLeapYear($startYear))))) { + $startDay = 30; + } + + return $startDay; + } + + private static function getEndDay(int $endDay, int &$endMonth, int &$endYear, int $startDay, bool $methodUS): int + { + if ($endDay == 31) { + if ($methodUS && $startDay != 30) { + $endDay = 1; + if ($endMonth == 12) { + ++$endYear; + $endMonth = 1; + } else { + ++$endMonth; + } + } else { + $endDay = 30; + } + } + + return $endDay; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/EDate.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/EDate.php new file mode 100644 index 00000000..43af694f --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/EDate.php @@ -0,0 +1,45 @@ +getMessage(); + } + $adjustmentMonths = floor($adjustmentMonths); + + // Execute function + $PHPDateObject = Helpers::adjustDateByMonths($dateValue, $adjustmentMonths); + + return Helpers::returnIn3FormatsObject($PHPDateObject); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/EoMonth.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/EoMonth.php new file mode 100644 index 00000000..6b39a609 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/EoMonth.php @@ -0,0 +1,47 @@ +getMessage(); + } + $adjustmentMonths = floor($adjustmentMonths); + + // Execute function + $PHPDateObject = Helpers::adjustDateByMonths($dateValue, $adjustmentMonths + 1); + $adjustDays = (int) $PHPDateObject->format('d'); + $adjustDaysString = '-' . $adjustDays . ' days'; + $PHPDateObject->modify($adjustDaysString); + + return Helpers::returnIn3FormatsObject($PHPDateObject); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php new file mode 100644 index 00000000..48300642 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php @@ -0,0 +1,291 @@ +getMessage(); + } + } + + /** + * getTimeValue. + * + * @param string $timeValue + * + * @return mixed Excel date/time serial value, or string if error + */ + public static function getTimeValue($timeValue) + { + $saveReturnDateType = Functions::getReturnDateType(); + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); + $timeValue = TimeValue::funcTimeValue($timeValue); + Functions::setReturnDateType($saveReturnDateType); + + return $timeValue; + } + + public static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0) + { + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + $oMonth = (int) $PHPDateObject->format('m'); + $oYear = (int) $PHPDateObject->format('Y'); + + $adjustmentMonthsString = (string) $adjustmentMonths; + if ($adjustmentMonths > 0) { + $adjustmentMonthsString = '+' . $adjustmentMonths; + } + if ($adjustmentMonths != 0) { + $PHPDateObject->modify($adjustmentMonthsString . ' months'); + } + $nMonth = (int) $PHPDateObject->format('m'); + $nYear = (int) $PHPDateObject->format('Y'); + + $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12); + if ($monthDiff != $adjustmentMonths) { + $adjustDays = (int) $PHPDateObject->format('d'); + $adjustDaysString = '-' . $adjustDays . ' days'; + $PHPDateObject->modify($adjustDaysString); + } + + return $PHPDateObject; + } + + /** + * Help reduce perceived complexity of some tests. + * + * @param mixed $value + * @param mixed $altValue + */ + public static function replaceIfEmpty(&$value, $altValue): void + { + $value = $value ?: $altValue; + } + + /** + * Adjust year in ambiguous situations. + */ + public static function adjustYear(string $testVal1, string $testVal2, string &$testVal3): void + { + if (!is_numeric($testVal1) || $testVal1 < 31) { + if (!is_numeric($testVal2) || $testVal2 < 12) { + if (is_numeric($testVal3) && $testVal3 < 12) { + $testVal3 += 2000; + } + } + } + } + + /** + * Return result in one of three formats. + * + * @return mixed + */ + public static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false) + { + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { + return new DateTime( + $dateArray['year'] + . '-' . $dateArray['month'] + . '-' . $dateArray['day'] + . ' ' . $dateArray['hour'] + . ':' . $dateArray['minute'] + . ':' . $dateArray['second'] + ); + } + $excelDateValue = + Date::formattedPHPToExcel( + $dateArray['year'], + $dateArray['month'], + $dateArray['day'], + $dateArray['hour'], + $dateArray['minute'], + $dateArray['second'] + ); + if ($retType === Functions::RETURNDATE_EXCEL) { + return $noFrac ? floor($excelDateValue) : (float) $excelDateValue; + } + // RETURNDATE_UNIX_TIMESTAMP) + + return (int) Date::excelToTimestamp($excelDateValue); + } + + /** + * Return result in one of three formats. + * + * @return mixed + */ + public static function returnIn3FormatsFloat(float $excelDateValue) + { + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_EXCEL) { + return $excelDateValue; + } + if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { + return (int) Date::excelToTimestamp($excelDateValue); + } + // RETURNDATE_PHP_DATETIME_OBJECT + + return Date::excelToDateTimeObject($excelDateValue); + } + + /** + * Return result in one of three formats. + * + * @return mixed + */ + public static function returnIn3FormatsObject(DateTime $PHPDateObject) + { + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) { + return $PHPDateObject; + } + if ($retType === Functions::RETURNDATE_EXCEL) { + return (float) Date::PHPToExcel($PHPDateObject); + } + // RETURNDATE_UNIX_TIMESTAMP + + return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject)); + } + + private static function baseDate(): int + { + if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { + return 0; + } + if (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) { + return 0; + } + + return 1; + } + + /** + * Many functions accept null/false/true argument treated as 0/0/1. + * + * @param mixed $number + */ + public static function nullFalseTrueToNumber(&$number, bool $allowBool = true): void + { + $number = Functions::flattenSingleValue($number); + $nullVal = self::baseDate(); + if ($number === null) { + $number = $nullVal; + } elseif ($allowBool && is_bool($number)) { + $number = $nullVal + (int) $number; + } + } + + /** + * Many functions accept null argument treated as 0. + * + * @param mixed $number + * + * @return float|int + */ + public static function validateNumericNull($number) + { + $number = Functions::flattenSingleValue($number); + if ($number === null) { + return 0; + } + if (is_numeric($number)) { + return $number; + } + + throw new Exception(Functions::VALUE()); + } + + /** + * Many functions accept null/false/true argument treated as 0/0/1. + * + * @param mixed $number + * + * @return float + */ + public static function validateNotNegative($number) + { + if (!is_numeric($number)) { + throw new Exception(Functions::VALUE()); + } + if ($number >= 0) { + return (float) $number; + } + + throw new Exception(Functions::NAN()); + } + + public static function silly1900(DateTime $PHPDateObject, string $mod = '-1 day'): void + { + $isoDate = $PHPDateObject->format('c'); + if ($isoDate < '1900-03-01') { + $PHPDateObject->modify($mod); + } + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Hour.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Hour.php new file mode 100644 index 00000000..98d4570d --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Hour.php @@ -0,0 +1,44 @@ +getMessage(); + } + + // Execute function + $timeValue = fmod($timeValue, 1); + $timeValue = Date::excelToDateTimeObject($timeValue); + + return (int) $timeValue->format('H'); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/IsoWeekNum.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/IsoWeekNum.php new file mode 100644 index 00000000..41959d9a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/IsoWeekNum.php @@ -0,0 +1,55 @@ +getMessage(); + } + + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + Helpers::silly1900($PHPDateObject); + + return (int) $PHPDateObject->format('W'); + } + + private static function apparentBug($dateValue): bool + { + if (Date::getExcelCalendar() !== DATE::CALENDAR_MAC_1904) { + if (is_bool($dateValue)) { + return true; + } + if (is_numeric($dateValue) && !((int) $dateValue)) { + return true; + } + } + + return false; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Minute.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Minute.php new file mode 100644 index 00000000..a1747ec9 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Minute.php @@ -0,0 +1,44 @@ +getMessage(); + } + + // Execute function + $timeValue = fmod($timeValue, 1); + $timeValue = Date::excelToDateTimeObject($timeValue); + + return (int) $timeValue->format('i'); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php new file mode 100644 index 00000000..a9fb8ece --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Month.php @@ -0,0 +1,40 @@ +getMessage(); + } + if ($dateValue < 1 && Date::getExcelCalendar() === DATE::CALENDAR_WINDOWS_1900) { + return 1; + } + + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + + return (int) $PHPDateObject->format('n'); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php new file mode 100644 index 00000000..c700c834 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php @@ -0,0 +1,102 @@ +getMessage(); + } + + // Execute function + $startDow = self::calcStartDow($startDate); + $endDow = self::calcEndDow($endDate); + $wholeWeekDays = (int) floor(($endDate - $startDate) / 7) * 5; + $partWeekDays = self::calcPartWeekDays($startDow, $endDow); + + // Test any extra holiday parameters + $holidayCountedArray = []; + foreach ($holidayArray as $holidayDate) { + if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { + if ((WeekDay::funcWeekDay($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) { + --$partWeekDays; + $holidayCountedArray[] = $holidayDate; + } + } + } + + return self::applySign($wholeWeekDays + $partWeekDays, $sDate, $eDate); + } + + private static function calcStartDow(float $startDate): int + { + $startDow = 6 - (int) WeekDay::funcWeekDay($startDate, 2); + if ($startDow < 0) { + $startDow = 5; + } + + return $startDow; + } + + private static function calcEndDow(float $endDate): int + { + $endDow = (int) WeekDay::funcWeekDay($endDate, 2); + if ($endDow >= 6) { + $endDow = 0; + } + + return $endDow; + } + + private static function calcPartWeekDays(int $startDow, int $endDow): int + { + $partWeekDays = $endDow + $startDow; + if ($partWeekDays > 5) { + $partWeekDays -= 5; + } + + return $partWeekDays; + } + + private static function applySign(int $result, float $sDate, float $eDate) + { + return ($sDate > $eDate) ? -$result : $result; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Now.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Now.php new file mode 100644 index 00000000..6e6bd171 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Now.php @@ -0,0 +1,34 @@ +format('c')); + + return is_array($dateArray) ? Helpers::returnIn3FormatsArray($dateArray) : Functions::VALUE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Second.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Second.php new file mode 100644 index 00000000..c4749993 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Second.php @@ -0,0 +1,44 @@ +getMessage(); + } + + // Execute function + $timeValue = fmod($timeValue, 1); + $timeValue = Date::excelToDateTimeObject($timeValue); + + return (int) $timeValue->format('s'); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php new file mode 100644 index 00000000..450f9d50 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php @@ -0,0 +1,116 @@ +getMessage(); + } + + self::adjustSecond($second, $minute); + self::adjustMinute($minute, $hour); + + if ($hour > 23) { + $hour = $hour % 24; + } elseif ($hour < 0) { + return Functions::NAN(); + } + + // Execute function + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_EXCEL) { + $calendar = Date::getExcelCalendar(); + $date = (int) ($calendar !== Date::CALENDAR_WINDOWS_1900); + + return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second); + } + if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { + return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600 + } + // RETURNDATE_PHP_DATETIME_OBJECT + // Hour has already been normalized (0-23) above + $phpDateObject = new DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second); + + return $phpDateObject; + } + + private static function adjustSecond(int &$second, int &$minute): void + { + if ($second < 0) { + $minute += floor($second / 60); + $second = 60 - abs($second % 60); + if ($second == 60) { + $second = 0; + } + } elseif ($second >= 60) { + $minute += floor($second / 60); + $second = $second % 60; + } + } + + private static function adjustMinute(int &$minute, int &$hour): void + { + if ($minute < 0) { + $hour += floor($minute / 60); + $minute = 60 - abs($minute % 60); + if ($minute == 60) { + $minute = 0; + } + } elseif ($minute >= 60) { + $hour += floor($minute / 60); + $minute = $minute % 60; + } + } + + private static function toIntWithNullBool($value): int + { + $value = Functions::flattenSingleValue($value); + $value = $value ?? 0; + if (is_bool($value)) { + $value = (int) $value; + } + if (!is_numeric($value)) { + throw new Exception(Functions::VALUE()); + } + + return (int) $value; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php new file mode 100644 index 00000000..2366b1d6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php @@ -0,0 +1,61 @@ + 24) { + $arraySplit[0] = ($arraySplit[0] % 24); + $timeValue = implode(':', $arraySplit); + } + + $PHPDateArray = date_parse($timeValue); + $retValue = Functions::VALUE(); + if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) { + // OpenOffice-specific code removed - it works just like Excel + $excelDateValue = Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1; + + $retType = Functions::getReturnDateType(); + if ($retType === Functions::RETURNDATE_EXCEL) { + $retValue = (float) $excelDateValue; + } elseif ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) { + $retValue = (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600; + } else { + $retValue = new DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']); + } + } + + return $retValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Today.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Today.php new file mode 100644 index 00000000..5e459410 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Today.php @@ -0,0 +1,34 @@ +format('c')); + + return is_array($dateArray) ? Helpers::returnIn3FormatsArray($dateArray, true) : Functions::VALUE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php new file mode 100644 index 00000000..15811ee5 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php @@ -0,0 +1,80 @@ +getMessage(); + } + + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + Helpers::silly1900($PHPDateObject); + $DoW = (int) $PHPDateObject->format('w'); + + switch ($style) { + case 1: + ++$DoW; + + break; + case 2: + $DoW = self::dow0Becomes7($DoW); + + break; + case 3: + $DoW = self::dow0Becomes7($DoW) - 1; + + break; + } + + return $DoW; + } + + private static function validateStyle($style): int + { + $style = Functions::flattenSingleValue($style); + + if (!is_numeric($style)) { + throw new Exception(Functions::VALUE()); + } + $style = (int) $style; + if (($style < 1) || ($style > 3)) { + throw new Exception(Functions::NAN()); + } + + return $style; + } + + private static function dow0Becomes7(int $DoW): int + { + return ($DoW === 0) ? 7 : $DoW; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php new file mode 100644 index 00000000..1dd15edb --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php @@ -0,0 +1,130 @@ +getMessage(); + } + + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + if ($method == Constants::STARTWEEK_MONDAY_ISO) { + Helpers::silly1900($PHPDateObject); + + return (int) $PHPDateObject->format('W'); + } + if (self::buggyWeekNum1904($method, $origDateValueNull, $PHPDateObject)) { + return 0; + } + Helpers::silly1900($PHPDateObject, '+ 5 years'); // 1905 calendar matches + $dayOfYear = $PHPDateObject->format('z'); + $PHPDateObject->modify('-' . $dayOfYear . ' days'); + $firstDayOfFirstWeek = $PHPDateObject->format('w'); + $daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7; + $daysInFirstWeek += 7 * !$daysInFirstWeek; + $endFirstWeek = $daysInFirstWeek - 1; + $weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7); + + return (int) $weekOfYear; + } + + /** + * Validate dateValue parameter. + * + * @param mixed $dateValue + */ + private static function validateDateValue($dateValue): float + { + if (is_bool($dateValue)) { + throw new Exception(Functions::VALUE()); + } + + return Helpers::getDateValue($dateValue); + } + + /** + * Validate method parameter. + * + * @param mixed $method + */ + private static function validateMethod($method): int + { + if ($method === null) { + $method = Constants::STARTWEEK_SUNDAY; + } + $method = Functions::flattenSingleValue($method); + if (!is_numeric($method)) { + throw new Exception(Functions::VALUE()); + } + + $method = (int) $method; + if (!array_key_exists($method, Constants::METHODARR)) { + throw new Exception(Functions::NAN()); + } + $method = Constants::METHODARR[$method]; + + return $method; + } + + private static function buggyWeekNum1900(int $method): bool + { + return $method === Constants::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_WINDOWS_1900; + } + + private static function buggyWeekNum1904(int $method, bool $origNull, DateTime $dateObject): bool + { + // This appears to be another Excel bug. + + return $method === Constants::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_MAC_1904 && !$origNull && $dateObject->format('Y-m-d') === '1904-01-01'; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php new file mode 100644 index 00000000..f812624e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php @@ -0,0 +1,182 @@ +getMessage(); + } + + $startDate = (float) floor($startDate); + $endDays = (int) floor($endDays); + // If endDays is 0, we always return startDate + if ($endDays == 0) { + return $startDate; + } + if ($endDays < 0) { + return self::decrementing($startDate, $endDays, $holidayArray); + } + + return self::incrementing($startDate, $endDays, $holidayArray); + } + + /** + * Use incrementing logic to determine Workday. + * + * @return mixed + */ + private static function incrementing(float $startDate, int $endDays, array $holidayArray) + { + // Adjust the start date if it falls over a weekend + + $startDoW = WeekDay::funcWeekDay($startDate, 3); + if (WeekDay::funcWeekDay($startDate, 3) >= 5) { + $startDate += 7 - $startDoW; + --$endDays; + } + + // Add endDays + $endDate = (float) $startDate + ((int) ($endDays / 5) * 7); + $endDays = $endDays % 5; + while ($endDays > 0) { + ++$endDate; + // Adjust the calculated end date if it falls over a weekend + $endDow = WeekDay::funcWeekDay($endDate, 3); + if ($endDow >= 5) { + $endDate += 7 - $endDow; + } + --$endDays; + } + + // Test any extra holiday parameters + if (!empty($holidayArray)) { + $endDate = self::incrementingArray($startDate, $endDate, $holidayArray); + } + + return Helpers::returnIn3FormatsFloat($endDate); + } + + private static function incrementingArray(float $startDate, float $endDate, array $holidayArray): float + { + $holidayCountedArray = $holidayDates = []; + foreach ($holidayArray as $holidayDate) { + if (WeekDay::funcWeekDay($holidayDate, 3) < 5) { + $holidayDates[] = $holidayDate; + } + } + sort($holidayDates, SORT_NUMERIC); + foreach ($holidayDates as $holidayDate) { + if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) { + if (!in_array($holidayDate, $holidayCountedArray)) { + ++$endDate; + $holidayCountedArray[] = $holidayDate; + } + } + // Adjust the calculated end date if it falls over a weekend + $endDoW = WeekDay::funcWeekDay($endDate, 3); + if ($endDoW >= 5) { + $endDate += 7 - $endDoW; + } + } + + return $endDate; + } + + /** + * Use decrementing logic to determine Workday. + * + * @return mixed + */ + private static function decrementing(float $startDate, int $endDays, array $holidayArray) + { + // Adjust the start date if it falls over a weekend + + $startDoW = WeekDay::funcWeekDay($startDate, 3); + if (WeekDay::funcWeekDay($startDate, 3) >= 5) { + $startDate += -$startDoW + 4; + ++$endDays; + } + + // Add endDays + $endDate = (float) $startDate + ((int) ($endDays / 5) * 7); + $endDays = $endDays % 5; + while ($endDays < 0) { + --$endDate; + // Adjust the calculated end date if it falls over a weekend + $endDow = WeekDay::funcWeekDay($endDate, 3); + if ($endDow >= 5) { + $endDate += 4 - $endDow; + } + ++$endDays; + } + + // Test any extra holiday parameters + if (!empty($holidayArray)) { + $endDate = self::decrementingArray($startDate, $endDate, $holidayArray); + } + + return Helpers::returnIn3FormatsFloat($endDate); + } + + private static function decrementingArray(float $startDate, float $endDate, array $holidayArray): float + { + $holidayCountedArray = $holidayDates = []; + foreach ($holidayArray as $holidayDate) { + if (WeekDay::funcWeekDay($holidayDate, 3) < 5) { + $holidayDates[] = $holidayDate; + } + } + rsort($holidayDates, SORT_NUMERIC); + foreach ($holidayDates as $holidayDate) { + if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) { + if (!in_array($holidayDate, $holidayCountedArray)) { + --$endDate; + $holidayCountedArray[] = $holidayDate; + } + } + // Adjust the calculated end date if it falls over a weekend + $endDoW = WeekDay::funcWeekDay($endDate, 3); + if ($endDoW >= 5) { + $endDate += -$endDoW + 4; + } + } + + return $endDate; + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Year.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Year.php new file mode 100644 index 00000000..5fcac739 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Year.php @@ -0,0 +1,40 @@ +getMessage(); + } + + if ($dateValue < 1 && Date::getExcelCalendar() === DATE::CALENDAR_WINDOWS_1900) { + return 1900; + } + // Execute function + $PHPDateObject = Date::excelToDateTimeObject($dateValue); + + return (int) $PHPDateObject->format('Y'); + } +} diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php new file mode 100644 index 00000000..a99b1c7f --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php @@ -0,0 +1,120 @@ +getMessage(); + } + + switch ($method) { + case 0: + return Days360::funcDays360($startDate, $endDate) / 360; + case 1: + return self::method1($startDate, $endDate); + case 2: + return DateDif::funcDateDif($startDate, $endDate) / 360; + case 3: + return DateDif::funcDateDif($startDate, $endDate) / 365; + case 4: + return Days360::funcDays360($startDate, $endDate, true) / 360; + } + + return Functions::NAN(); + } + + /** + * Excel 1900 calendar treats date argument of null as 1900-01-00. Really. + * + * @param mixed $startDate + * @param mixed $endDate + */ + private static function excelBug(float $sDate, $startDate, $endDate, int $method): float + { + if (Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_OPENOFFICE && Date::getExcelCalendar() !== Date::CALENDAR_MAC_1904) { + if ($endDate === null && $startDate !== null) { + if (Month::funcMonth($sDate) == 12 && Day::funcDay($sDate) === 31 && $method === 0) { + $sDate += 2; + } else { + ++$sDate; + } + } + } + + return $sDate; + } + + private static function method1(float $startDate, float $endDate): float + { + $days = DateDif::funcDateDif($startDate, $endDate); + $startYear = Year::funcYear($startDate); + $endYear = Year::funcYear($endDate); + $years = $endYear - $startYear + 1; + $startMonth = Month::funcMonth($startDate); + $startDay = Day::funcDay($startDate); + $endMonth = Month::funcMonth($endDate); + $endDay = Day::funcDay($endDate); + $startMonthDay = 100 * $startMonth + $startDay; + $endMonthDay = 100 * $endMonth + $endDay; + if ($years == 1) { + $tmpCalcAnnualBasis = 365 + (int) Helpers::isLeapYear($endYear); + } elseif ($years == 2 && $startMonthDay >= $endMonthDay) { + if (Helpers::isLeapYear($startYear)) { + $tmpCalcAnnualBasis = 365 + (int) ($startMonthDay <= 229); + } elseif (Helpers::isLeapYear($endYear)) { + $tmpCalcAnnualBasis = 365 + (int) ($endMonthDay >= 229); + } else { + $tmpCalcAnnualBasis = 365; + } + } else { + $tmpCalcAnnualBasis = 0; + for ($year = $startYear; $year <= $endYear; ++$year) { + $tmpCalcAnnualBasis += 365 + (int) Helpers::isLeapYear($year); + } + $tmpCalcAnnualBasis /= $years; + } + + return $days / $tmpCalcAnnualBasis; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php new file mode 100644 index 00000000..c56c7431 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php @@ -0,0 +1,71 @@ +compatibilityMode = Functions::getCompatibilityMode(); + $this->excelCalendar = Date::getExcelCalendar(); + $this->returnDateType = Functions::getReturnDateType(); + $this->spreadsheet = new Spreadsheet(); + $this->sheet = $this->spreadsheet->getActiveSheet(); + } + + protected function tearDown(): void + { + Date::setExcelCalendar($this->excelCalendar); + Functions::setCompatibilityMode($this->compatibilityMode); + Functions::setReturnDateType($this->returnDateType); + $this->spreadsheet->disconnectWorksheets(); + $this->spreadsheet = null; + $this->sheet = null; + } + + protected static function setMac1904(): void + { + Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + } + + protected static function setUnixReturn(): void + { + Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP); + } + + protected static function setObjectReturn(): void + { + Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT); + } + + protected static function setOpenOffice(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + } + + /** + * @param mixed $expectedResult + */ + protected function mightHaveException($expectedResult): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcException::class); + } + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php index db8e29a1..6c394087 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php @@ -2,32 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class DateDifTest extends TestCase +class DateDifTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerDATEDIF * * @param mixed $expectedResult - * @param $startDate - * @param $endDate - * @param $unit */ - public function testDATEDIF($expectedResult, $startDate, $endDate, $unit): void + public function testDATEDIF($expectedResult, string $formula): void { - $result = DateTime::DATEDIF($startDate, $endDate, $unit); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('A1')->setValue("=DATEDIF($formula)"); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerDATEDIF() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php index aad59729..354e6f3b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php @@ -2,42 +2,22 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Datefunc; -class DateTest extends TestCase +class DateTest extends AllSetupTeardown { - private $returnDateType; - - private $excelCalendar; - - protected function setUp(): void - { - $this->returnDateType = Functions::getReturnDateType(); - $this->excelCalendar = Date::getExcelCalendar(); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - } - - protected function tearDown(): void - { - Functions::setReturnDateType($this->returnDateType); - Date::setExcelCalendar($this->excelCalendar); - } - /** * @dataProvider providerDATE * * @param mixed $expectedResult - * @param $year - * @param $month - * @param $day */ - public function testDATE($expectedResult, $year, $month, $day): void + public function testDATE($expectedResult, string $formula): void { - $result = DateTime::DATE($year, $month, $day); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('A1')->setValue("=DATE($formula)"); + self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerDATE() @@ -47,18 +27,17 @@ class DateTest extends TestCase public function testDATEtoUnixTimestamp(): void { - Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP); + self::setUnixReturn(); - $result = DateTime::DATE(2012, 1, 31); + $result = Datefunc::funcDate(2012, 1, 31); // 32-bit safe self::assertEquals(1327968000, $result); - self::assertEqualsWithDelta(1327968000, $result, 1E-8); } public function testDATEtoDateTimeObject(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT); + self::setObjectReturn(); - $result = DateTime::DATE(2012, 1, 31); + $result = Datefunc::funcDate(2012, 1, 31); // Must return an object... self::assertIsObject($result); // ... of the correct type @@ -69,17 +48,12 @@ class DateTest extends TestCase public function testDATEwith1904Calendar(): void { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); + self::setMac1904(); - $result = DateTime::DATE(1918, 11, 11); + $result = Datefunc::funcDate(1918, 11, 11); self::assertEquals($result, 5428); - } - public function testDATEwith1904CalendarError(): void - { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - - $result = DateTime::DATE(1901, 1, 31); + $result = Datefunc::funcDate(1901, 1, 31); self::assertEquals($result, '#NUM!'); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php index 72e036f9..fc432bbe 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php @@ -4,50 +4,33 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; use DateTimeImmutable; use DateTimeInterface; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\DateValue; -class DateValueTest extends TestCase +class DateValueTest extends AllSetupTeardown { - private $returnDateType; - - private $excelCalendar; - - protected function setUp(): void - { - $this->returnDateType = Functions::getReturnDateType(); - $this->excelCalendar = Date::getExcelCalendar(); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - } - - protected function tearDown(): void - { - Functions::setReturnDateType($this->returnDateType); - Date::setExcelCalendar($this->excelCalendar); - } - /** * @dataProvider providerDATEVALUE * * @param mixed $expectedResult - * @param $dateValue */ - public function testDATEVALUE($expectedResult, $dateValue): void + public function testDATEVALUE($expectedResult, string $dateValue): void { + $this->sheet->getCell('B1')->setValue('1954-07-20'); // Loop to avoid extraordinarily rare edge case where first calculation // and second do not take place on same day. + $row = 0; do { + ++$row; $dtStart = new DateTimeImmutable(); $startDay = $dtStart->format('d'); if (is_string($expectedResult)) { $replYMD = str_replace('Y', date('Y'), $expectedResult); if ($replYMD !== $expectedResult) { - $expectedResult = DateTime::DATEVALUE($replYMD); + $expectedResult = DateValue::funcDateValue($replYMD); } } - $result = DateTime::DATEVALUE($dateValue); + $this->sheet->getCell("A$row")->setValue("=DATEVALUE($dateValue)"); + $result = $this->sheet->getCell("A$row")->getCalculatedValue(); $dtEnd = new DateTimeImmutable(); $endDay = $dtEnd->format('d'); } while ($startDay !== $endDay); @@ -61,18 +44,18 @@ class DateValueTest extends TestCase public function testDATEVALUEtoUnixTimestamp(): void { - Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP); + self::setUnixReturn(); - $result = DateTime::DATEVALUE('2012-1-31'); + $result = DateValue::funcDateValue('2012-1-31'); self::assertEquals(1327968000, $result); self::assertEqualsWithDelta(1327968000, $result, 1E-8); } public function testDATEVALUEtoDateTimeObject(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT); + self::setObjectReturn(); - $result = DateTime::DATEVALUE('2012-1-31'); + $result = DateValue::funcDateValue('2012-1-31'); // Must return an object... self::assertIsObject($result); // ... of the correct type @@ -83,10 +66,10 @@ class DateValueTest extends TestCase public function testDATEVALUEwith1904Calendar(): void { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - self::assertEquals(5428, DateTime::DATEVALUE('1918-11-11')); - self::assertEquals(0, DateTime::DATEVALUE('1904-01-01')); - self::assertEquals('#VALUE!', DateTime::DATEVALUE('1903-12-31')); - self::assertEquals('#VALUE!', DateTime::DATEVALUE('1900-02-29')); + self::setMac1904(); + self::assertEquals(5428, DateValue::funcDateValue('1918-11-11')); + self::assertEquals(0, DateValue::funcDateValue('1904-01-01')); + self::assertEquals('#VALUE!', DateValue::funcDateValue('1903-12-31')); + self::assertEquals('#VALUE!', DateValue::funcDateValue('1900-02-29')); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php index 482e068d..e50475cf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php @@ -2,56 +2,43 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class DayTest extends TestCase +class DayTest extends AllSetupTeardown { - private $compatibilityMode; - - private $returnDateType; - - private $excelCalendar; - - protected function setUp(): void - { - $this->compatibilityMode = Functions::getCompatibilityMode(); - $this->returnDateType = Functions::getReturnDateType(); - $this->excelCalendar = Date::getExcelCalendar(); - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - - protected function tearDown(): void - { - Functions::setCompatibilityMode($this->compatibilityMode); - Functions::setReturnDateType($this->returnDateType); - Date::setExcelCalendar($this->excelCalendar); - } - /** * @dataProvider providerDAY * * @param mixed $expectedResultExcel - * @param mixed $expectedResultOpenOffice - * @param $dateTimeValue */ - public function testDAY($expectedResultExcel, $expectedResultOpenOffice, $dateTimeValue): void + public function testDAY($expectedResultExcel, string $dateTimeValue): void { - $resultExcel = DateTime::DAYOFMONTH($dateTimeValue); - self::assertEqualsWithDelta($expectedResultExcel, $resultExcel, 1E-8); - - Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); - - $resultOpenOffice = DateTime::DAYOFMONTH($dateTimeValue); - self::assertEqualsWithDelta($expectedResultOpenOffice, $resultOpenOffice, 1E-8); + $this->mightHaveException($expectedResultExcel); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('A1')->setValue("=DAY($dateTimeValue)"); + self::assertSame($expectedResultExcel, $sheet->getCell('A1')->getCalculatedValue()); } public function providerDAY() { return require 'tests/data/Calculation/DateTime/DAY.php'; } + + /** + * @dataProvider providerDAYOpenOffice + * + * @param mixed $expectedResultOpenOffice + */ + public function testDAYOpenOffice($expectedResultOpenOffice, string $dateTimeValue): void + { + self::setOpenOffice(); + $this->mightHaveException($expectedResultOpenOffice); + $sheet = $this->sheet; + $sheet->getCell('A2')->setValue("=DAY($dateTimeValue)"); + self::assertSame($expectedResultOpenOffice, $sheet->getCell('A2')->getCalculatedValue()); + } + + public function providerDAYOpenOffice() + { + return require 'tests/data/Calculation/DateTime/DAYOpenOffice.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php index 47449e0d..5d6ba29e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php @@ -2,32 +2,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class Days360Test extends TestCase +class Days360Test extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerDAYS360 * * @param mixed $expectedResult - * @param $startDate - * @param $endDate - * @param $method */ - public function testDAYS360($expectedResult, $startDate, $endDate, $method): void + public function testDAYS360($expectedResult, string $formula): void { - $result = DateTime::DAYS360($startDate, $endDate, $method); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('2000-02-29'); + $sheet->getCell('C1')->setValue('2000-03-31'); + $sheet->getCell('A1')->setValue("=DAYS360($formula)"); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerDAYS360() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php index fe31dfcc..8b3ea392 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php @@ -2,35 +2,44 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use DateTime; +use DateTimeImmutable; +use Exception; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Days; -class DaysTest extends TestCase +class DaysTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerDAYS * * @param mixed $expectedResult - * @param $endDate - * @param $startDate */ - public function testDAYS($expectedResult, $endDate, $startDate): void + public function testDAYS($expectedResult, string $formula): void { - $result = DateTime::DAYS($endDate, $startDate); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('C1')->setValue('1954-11-30'); + $sheet->getCell('A1')->setValue("=DAYS($formula)"); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerDAYS() { return require 'tests/data/Calculation/DateTime/DAYS.php'; } + + public function testObject(): void + { + $obj1 = new DateTime('2000-3-31'); + $obj2 = new DateTimeImmutable('2000-2-29'); + self::assertSame(31, Days::funcDays($obj1, $obj2)); + } + + public function testNonDateObject(): void + { + $obj1 = new Exception(); + $obj2 = new DateTimeImmutable('2000-2-29'); + self::assertSame('#VALUE!', Days::funcDays($obj1, $obj2)); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php index a887ba5b..384e1aec 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php @@ -2,31 +2,22 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\EDate; -class EDateTest extends TestCase +class EDateTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerEDATE * * @param mixed $expectedResult - * @param $dateValue - * @param $adjustmentMonths */ - public function testEDATE($expectedResult, $dateValue, $adjustmentMonths): void + public function testEDATE($expectedResult, string $formula): void { - $result = DateTime::EDATE($dateValue, $adjustmentMonths); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=EDATE($formula)"); + $sheet->getCell('B1')->setValue('1954-11-23'); + self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerEDATE() @@ -36,18 +27,18 @@ class EDateTest extends TestCase public function testEDATEtoUnixTimestamp(): void { - Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP); + self::setUnixReturn(); - $result = DateTime::EDATE('2012-1-26', -1); + $result = EDate::funcEDate('2012-1-26', -1); self::assertEquals(1324857600, $result); self::assertEqualsWithDelta(1324857600, $result, 1E-8); } public function testEDATEtoDateTimeObject(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT); + self::setObjectReturn(); - $result = DateTime::EDATE('2012-1-26', -1); + $result = EDate::funcEDate('2012-1-26', -1); // Must return an object... self::assertIsObject($result); // ... of the correct type diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php index f9c54039..1af81c9f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php @@ -2,31 +2,22 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\EoMonth; -class EoMonthTest extends TestCase +class EoMonthTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerEOMONTH * * @param mixed $expectedResult - * @param $dateValue - * @param $adjustmentMonths */ - public function testEOMONTH($expectedResult, $dateValue, $adjustmentMonths): void + public function testEOMONTH($expectedResult, string $formula): void { - $result = DateTime::EOMONTH($dateValue, $adjustmentMonths); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=EOMONTH($formula)"); + $sheet->getCell('B1')->setValue('1954-11-23'); + self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerEOMONTH() @@ -36,23 +27,22 @@ class EoMonthTest extends TestCase public function testEOMONTHtoUnixTimestamp(): void { - Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP); + self::setUnixReturn(); - $result = DateTime::EOMONTH('2012-1-26', -1); + $result = EoMonth::funcEomonth('2012-1-26', -1); self::assertEquals(1325289600, $result); - self::assertEqualsWithDelta(1325289600, $result, 1E-8); } public function testEOMONTHtoDateTimeObject(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT); + self::setObjectReturn(); - $result = DateTime::EOMONTH('2012-1-26', -1); + $result = EoMonth::funcEomonth('2012-1-26', -1); // Must return an object... self::assertIsObject($result); // ... of the correct type self::assertTrue(is_a($result, 'DateTimeInterface')); // ... with the correct value - self::assertEquals($result->format('d-M-Y'), '31-Dec-2011'); + self::assertSame($result->format('d-M-Y'), '31-Dec-2011'); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php index 2d0cd5d1..99544b5a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php @@ -2,30 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class HourTest extends TestCase +class HourTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerHOUR * * @param mixed $expectedResult - * @param $dateTimeValue */ - public function testHOUR($expectedResult, $dateTimeValue): void + public function testHOUR($expectedResult, string $dateTimeValue): void { - $result = DateTime::HOUROFDAY($dateTimeValue); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=HOUR($dateTimeValue)"); + $sheet->getCell('B1')->setValue('1954-11-23 2:23:46'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerHOUR() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php index 1ef0080a..b27ca7d5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php @@ -2,34 +2,46 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class IsoWeekNumTest extends TestCase +class IsoWeekNumTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerISOWEEKNUM * * @param mixed $expectedResult - * @param mixed $dateValue + * @param string $dateValue */ public function testISOWEEKNUM($expectedResult, $dateValue): void { - $result = DateTime::ISOWEEKNUM($dateValue); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=ISOWEEKNUM($dateValue)"); + $sheet->getCell('B1')->setValue('1954-11-23'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerISOWEEKNUM() { return require 'tests/data/Calculation/DateTime/ISOWEEKNUM.php'; } + + /** + * @dataProvider providerISOWEEKNUM1904 + * + * @param mixed $expectedResult + * @param string $dateValue + */ + public function testISOWEEKNUM1904($expectedResult, $dateValue): void + { + $this->mightHaveException($expectedResult); + self::setMac1904(); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=ISOWEEKNUM($dateValue)"); + $sheet->getCell('B1')->setValue('1954-11-23'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); + } + + public function providerISOWEEKNUM1904() + { + return require 'tests/data/Calculation/DateTime/ISOWEEKNUM1904.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php index 8472c6de..cbc2a1a4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php @@ -2,30 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class MinuteTest extends TestCase +class MinuteTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerMINUTE * * @param mixed $expectedResult - * @param $dateTimeValue */ - public function testMINUTE($expectedResult, $dateTimeValue): void + public function testMINUTE($expectedResult, string $dateTimeValue): void { - $result = DateTime::MINUTE($dateTimeValue); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=MINUTE($dateTimeValue)"); + $sheet->getCell('B1')->setValue('1954-11-23 2:23:46'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerMINUTE() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php index 62513702..a9f70229 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php @@ -2,30 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class MonthTest extends TestCase +class MonthTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerMONTH * * @param mixed $expectedResult - * @param $dateTimeValue */ - public function testMONTH($expectedResult, $dateTimeValue): void + public function testMONTH($expectedResult, string $dateTimeValue): void { - $result = DateTime::MONTHOFYEAR($dateTimeValue); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=MONTH($dateTimeValue)"); + $sheet->getCell('B1')->setValue('1954-11-23'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerMONTH() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MovedFunctionsTest.php new file mode 100644 index 00000000..d14f7d7d --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MovedFunctionsTest.php @@ -0,0 +1,63 @@ +format('s'); + $nowResult = DateTime::DATETIMENOW(); + $todayResult = DateTime::DATENOW(); + $dtEnd = new DateTimeImmutable(); + $endSecond = $dtEnd->format('s'); + } while ($startSecond !== $endSecond); + self::assertSame(DateTime::DAYOFMONTH($nowResult), DateTime::DAYOFMONTH($todayResult)); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php index e366c44e..568c661c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php @@ -2,29 +2,47 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class NetworkDaysTest extends TestCase +class NetworkDaysTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerNETWORKDAYS * * @param mixed $expectedResult + * @param mixed $arg1 + * @param mixed $arg2 */ - public function testNETWORKDAYS($expectedResult, ...$args): void + public function testNETWORKDAYS($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', ?array $arg3 = null): void { - $result = DateTime::NETWORKDAYS(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg2 !== null) { + $sheet->getCell('A2')->setValue($arg2); + } + $dateArray = []; + if (is_array($arg3)) { + if (array_key_exists(0, $arg3) && is_array($arg3[0])) { + $dateArray = $arg3[0]; + } else { + $dateArray = $arg3; + } + } + $dateIndex = 0; + foreach ($dateArray as $date) { + ++$dateIndex; + $sheet->getCell("C$dateIndex")->setValue($date); + } + $arrayArg = $dateIndex ? ", C1:C$dateIndex" : ''; + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=NETWORKDAYS()'); + } elseif ($arg2 === 'omitted') { + $sheet->getCell('B1')->setValue('=NETWORKDAYS(A1)'); + } else { + $sheet->getCell('B1')->setValue("=NETWORKDAYS(A1, A2$arrayArg)"); + } + self::assertEquals($expectedResult, $sheet->getCell('B1')->getCalculatedValue()); } public function providerNETWORKDAYS() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php index f139f703..e0f68c24 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php @@ -3,15 +3,12 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; use DateTimeImmutable; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; -class NowTest extends TestCase +class NowTest extends AllSetupTeardown { public function testNow(): void { - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $sheet = $this->sheet; // Loop to avoid rare edge case where first calculation // and second do not take place in same second. do { @@ -21,7 +18,6 @@ class NowTest extends TestCase $dtEnd = new DateTimeImmutable(); $endSecond = $dtEnd->format('s'); } while ($startSecond !== $endSecond); - //echo("\n"); var_dump($sheet->getCell('A1')->getCalculatedValue()); echo ("\n"); $sheet->setCellValue('B1', '=YEAR(A1)'); $sheet->setCellValue('C1', '=MONTH(A1)'); $sheet->setCellValue('D1', '=DAY(A1)'); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php index bc2b0752..03cef8bc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php @@ -2,30 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class SecondTest extends TestCase +class SecondTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerSECOND * * @param mixed $expectedResult - * @param $dateTimeValue */ - public function testSECOND($expectedResult, $dateTimeValue): void + public function testSECOND($expectedResult, string $dateTimeValue): void { - $result = DateTime::SECOND($dateTimeValue); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=SECOND($dateTimeValue)"); + $sheet->getCell('B1')->setValue('1954-11-23 2:23:46'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerSECOND() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php index 3ef58374..f33b5aac 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php @@ -2,39 +2,24 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Time; -class TimeTest extends TestCase +class TimeTest extends AllSetupTeardown { - private $returnDateType; - - private $calendar; - - protected function setUp(): void - { - $this->returnDateType = Functions::getReturnDateType(); - $this->calendar = Date::getExcelCalendar(); - } - - protected function tearDown(): void - { - Functions::setReturnDateType($this->returnDateType); - Date::setExcelCalendar($this->calendar); - } - /** * @dataProvider providerTIME * * @param mixed $expectedResult */ - public function testTIME($expectedResult, ...$args): void + public function testTIME($expectedResult, string $formula): void { - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - $result = DateTime::TIME(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('15'); + $sheet->getCell('B2')->setValue('32'); + $sheet->getCell('B3')->setValue('50'); + $sheet->getCell('A1')->setValue("=TIME($formula)"); + self::assertEqualsWithDelta($expectedResult, $sheet->getCell('A1')->getCalculatedValue(), 1E-8); } public function providerTIME() @@ -44,17 +29,17 @@ class TimeTest extends TestCase public function testTIMEtoUnixTimestamp(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC); + self::setUnixReturn(); - $result = DateTime::TIME(7, 30, 20); + $result = Time::funcTime(7, 30, 20); self::assertEqualsWithDelta(27020, $result, 1E-8); } public function testTIMEtoDateTimeObject(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT); + self::setObjectReturn(); - $result = DateTime::TIME(7, 30, 20); + $result = Time::funcTime(7, 30, 20); // Must return an object... self::assertIsObject($result); // ... of the correct type @@ -65,17 +50,14 @@ class TimeTest extends TestCase public function testTIME1904(): void { - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - $result = DateTime::TIME(0, 0, 0); + self::setMac1904(); + $result = Time::funcTime(0, 0, 0); self::assertEquals(0, $result); } public function testTIME1900(): void { - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - $result = DateTime::TIME(0, 0, 0); + $result = Time::funcTime(0, 0, 0); self::assertEquals(0, $result); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php index 04b8c058..f144c6f2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php @@ -2,20 +2,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\TimeValue; -class TimeValueTest extends TestCase +class TimeValueTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerTIMEVALUE * @@ -24,7 +14,11 @@ class TimeValueTest extends TestCase */ public function testTIMEVALUE($expectedResult, $timeValue): void { - $result = DateTime::TIMEVALUE($timeValue); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('03:45:52'); + $sheet->getCell('A1')->setValue("=TIMEVALUE($timeValue)"); + $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } @@ -35,18 +29,18 @@ class TimeValueTest extends TestCase public function testTIMEVALUEtoUnixTimestamp(): void { - Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP); + self::setUnixReturn(); - $result = DateTime::TIMEVALUE('7:30:20'); + $result = TimeValue::funcTimeValue('7:30:20'); self::assertEquals(23420, $result); self::assertEqualsWithDelta(23420, $result, 1E-8); } public function testTIMEVALUEtoDateTimeObject(): void { - Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT); + self::setObjectReturn(); - $result = DateTime::TIMEVALUE('7:30:20'); + $result = TimeValue::funcTimeValue('7:30:20'); // Must return an object... self::assertIsObject($result); // ... of the correct type diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TodayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TodayTest.php new file mode 100644 index 00000000..6ce82bfd --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TodayTest.php @@ -0,0 +1,34 @@ +sheet; + // Loop to avoid rare edge case where first calculation + // and second do not take place in same second. + do { + $dtStart = new DateTimeImmutable(); + $startSecond = $dtStart->format('s'); + $sheet->setCellValue('A1', '=TODAY()'); + $dtEnd = new DateTimeImmutable(); + $endSecond = $dtEnd->format('s'); + } while ($startSecond !== $endSecond); + $sheet->setCellValue('B1', '=YEAR(A1)'); + $sheet->setCellValue('C1', '=MONTH(A1)'); + $sheet->setCellValue('D1', '=DAY(A1)'); + $sheet->setCellValue('E1', '=HOUR(A1)'); + $sheet->setCellValue('F1', '=MINUTE(A1)'); + $sheet->setCellValue('G1', '=SECOND(A1)'); + self::assertSame((int) $dtStart->format('Y'), $sheet->getCell('B1')->getCalculatedValue()); + self::assertSame((int) $dtStart->format('m'), $sheet->getCell('C1')->getCalculatedValue()); + self::assertSame((int) $dtStart->format('d'), $sheet->getCell('D1')->getCalculatedValue()); + self::assertSame(0, $sheet->getCell('E1')->getCalculatedValue()); + self::assertSame(0, $sheet->getCell('F1')->getCalculatedValue()); + self::assertSame(0, $sheet->getCell('G1')->getCalculatedValue()); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php index 99aa6f7c..f1bc51f3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php @@ -2,33 +2,22 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Weekday; -class WeekDayTest extends TestCase +class WeekDayTest extends AllSetupTeardown { - private $excelCalendar; - - protected function setUp(): void - { - $this->excelCalendar = Date::getExcelCalendar(); - } - - protected function tearDown(): void - { - Date::setExcelCalendar($this->excelCalendar); - } - /** * @dataProvider providerWEEKDAY * * @param mixed $expectedResult */ - public function testWEEKDAY($expectedResult, ...$args): void + public function testWEEKDAY($expectedResult, string $formula): void { - $result = DateTime::WEEKDAY(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('A1')->setValue("=WEEKDAY($formula)"); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerWEEKDAY() @@ -38,9 +27,9 @@ class WeekDayTest extends TestCase public function testWEEKDAYwith1904Calendar(): void { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - self::assertEquals(7, DateTime::WEEKDAY('1904-01-02')); - self::assertEquals(6, DateTime::WEEKDAY('1904-01-01')); - self::assertEquals(6, DateTime::WEEKDAY(null)); + self::setMac1904(); + self::assertEquals(7, Weekday::funcWeekDay('1904-01-02')); + self::assertEquals(6, Weekday::funcWeekDay('1904-01-01')); + self::assertEquals(6, Weekday::funcWeekDay(null)); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php index 17119f28..c3e785f3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php @@ -2,33 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class WeekNumTest extends TestCase +class WeekNumTest extends AllSetupTeardown { - private $excelCalendar; - - protected function setUp(): void - { - $this->excelCalendar = Date::getExcelCalendar(); - } - - protected function tearDown(): void - { - Date::setExcelCalendar($this->excelCalendar); - } - /** * @dataProvider providerWEEKNUM * * @param mixed $expectedResult */ - public function testWEEKNUM($expectedResult, ...$args): void + public function testWEEKNUM($expectedResult, string $formula): void { - $result = DateTime::WEEKNUM(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('A1')->setValue("=WEEKNUM($formula)"); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerWEEKNUM() @@ -36,13 +23,23 @@ class WeekNumTest extends TestCase return require 'tests/data/Calculation/DateTime/WEEKNUM.php'; } - public function testWEEKNUMwith1904Calendar(): void + /** + * @dataProvider providerWEEKNUM1904 + * + * @param mixed $expectedResult + */ + public function testWEEKNUM1904($expectedResult, string $formula): void { - Date::setExcelCalendar(Date::CALENDAR_MAC_1904); - self::assertEquals(27, DateTime::WEEKNUM('2004-07-02')); - self::assertEquals(1, DateTime::WEEKNUM('1904-01-02')); - self::assertEquals(1, DateTime::WEEKNUM(null)); - // The following is a bug in Excel. - self::assertEquals(0, DateTime::WEEKNUM('1904-01-01')); + $this->mightHaveException($expectedResult); + self::setMac1904(); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('1954-11-23'); + $sheet->getCell('A1')->setValue("=WEEKNUM($formula)"); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); + } + + public function providerWEEKNUM1904() + { + return require 'tests/data/Calculation/DateTime/WEEKNUM1904.php'; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php index 4784e463..ec2a5402 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php @@ -2,29 +2,47 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class WorkDayTest extends TestCase +class WorkDayTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerWORKDAY * * @param mixed $expectedResult + * @param mixed $arg1 + * @param mixed $arg2 */ - public function testWORKDAY($expectedResult, ...$args): void + public function testWORKDAY($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', ?array $arg3 = null): void { - $result = DateTime::WORKDAY(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg2 !== null) { + $sheet->getCell('A2')->setValue($arg2); + } + $dateArray = []; + if (is_array($arg3)) { + if (array_key_exists(0, $arg3) && is_array($arg3[0])) { + $dateArray = $arg3[0]; + } else { + $dateArray = $arg3; + } + } + $dateIndex = 0; + foreach ($dateArray as $date) { + ++$dateIndex; + $sheet->getCell("C$dateIndex")->setValue($date); + } + $arrayArg = $dateIndex ? ", C1:C$dateIndex" : ''; + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=WORKDAY()'); + } elseif ($arg2 === 'omitted') { + $sheet->getCell('B1')->setValue('=WORKDAY(A1)'); + } else { + $sheet->getCell('B1')->setValue("=WORKDAY(A1, A2$arrayArg)"); + } + self::assertEquals($expectedResult, $sheet->getCell('B1')->getCalculatedValue()); } public function providerWORKDAY() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php index 05f11310..e6ac823a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php @@ -2,29 +2,39 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class YearFracTest extends TestCase +class YearFracTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerYEARFRAC * * @param mixed $expectedResult + * @param mixed $arg1 + * @param mixed $arg2 + * @param mixed $arg3 */ - public function testYEARFRAC($expectedResult, ...$args): void + public function testYEARFRAC($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', $arg3 = 'omitted'): void { - $result = DateTime::YEARFRAC(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg2 !== null) { + $sheet->getCell('A2')->setValue($arg2); + } + if ($arg3 !== null) { + $sheet->getCell('A3')->setValue($arg3); + } + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=YEARFRAC()'); + } elseif ($arg2 === 'omitted') { + $sheet->getCell('B1')->setValue('=YEARFRAC(A1)'); + } elseif ($arg3 === 'omitted') { + $sheet->getCell('B1')->setValue('=YEARFRAC(A1, A2)'); + } else { + $sheet->getCell('B1')->setValue('=YEARFRAC(A1, A2, A3)'); + } + self::assertEqualswithDelta($expectedResult, $sheet->getCell('B1')->getCalculatedValue(), 1E-6); } public function providerYEARFRAC() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php index bbdaf92a..7942f06c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php @@ -2,30 +2,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PHPUnit\Framework\TestCase; - -class YearTest extends TestCase +class YearTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900); - } - /** * @dataProvider providerYEAR * * @param mixed $expectedResult - * @param $dateTimeValue */ - public function testYEAR($expectedResult, $dateTimeValue): void + public function testYEAR($expectedResult, string $dateTimeValue): void { - $result = DateTime::YEAR($dateTimeValue); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue("=YEAR($dateTimeValue)"); + $sheet->getCell('B1')->setValue('1954-11-23'); + self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } public function providerYEAR() diff --git a/tests/data/Calculation/DateTime/DATE.php b/tests/data/Calculation/DateTime/DATE.php index 9acc6716..72816b76 100644 --- a/tests/data/Calculation/DateTime/DATE.php +++ b/tests/data/Calculation/DateTime/DATE.php @@ -1,319 +1,84 @@ [ - 6890, // '11th November 1918' - 18, 11, 11, - ], - 'Excel 1900 Calendar Base Date' => [ - 1, - 1900, 1, 1, - ], - 'Day before Excel mythical 1900 leap day' => [ - 59, - 1900, 2, 28, - ], - 'Excel mythical 1900 leap day' => [ - 60, - 1900, 2, 29, - ], - 'Day after Excel mythical 1900 leap day' => [ - 61, - 1900, 3, 1, - ], - 'Day after Excel actual 1904 leap day' => [ - 713, - 1901, 12, 13, - ], - 'signed 32-bit Unix Timestamp Earliest Date' => [ - 714, - 1901, 12, 14, - ], - 'Day before Excel 1904 Calendar Base Date' => [ - 1461, - 1903, 12, 31, - ], - 'Excel 1904 Calendar Base Date' => [ - 1462, - 1904, 1, 1, - ], - 'Day after Excel 1904 Calendar Base Date' => [ - 1463, - 1904, 1, 2, - ], - [ - 22269, - 1960, 12, 19, - ], - 'Unix Timestamp Base Date' => [ - 25569, - 1970, 1, 1, - ], - [ - 30292, - 1982, 12, 7, - ], - [ - 39611, - 2008, 6, 12, - ], - '32-bit signed Unix Timestamp Latest Date' => [ - 50424, - 2038, 1, 19, - ], - 'Day after 32-bit signed Unix Timestamp Latest Date' => [ - 50425, - 2038, 1, 20, - ], - [ - 39448, - 2008, 1, 1, - ], - [ - 39447, - 2008, 1, null, - ], - [ - 39446, - 2008, 1, -1, - ], - [ - 39417, - 2008, 1, -30, - ], - [ - 39416, - 2008, 1, -31, - ], - [ - 39082, - 2008, 1, -365, - ], - [ - 39508, - 2008, 3, 1, - ], - [ - 39507, - 2008, 3, null, - ], - [ - 39506, - 2008, 3, -1, - ], - [ - 39142, - 2008, 3, -365, - ], - [ - 39417, - 2008, null, 1, - ], - [ - 39387, - 2008, -1, 1, - ], - [ - 39083, - 2008, -11, 1, - ], - [ - 39052, - 2008, -12, 1, - ], - [ - 39022, - 2008, -13, 1, - ], - [ - 39051, - 2008, -13, 30, - ], - [ - 39021, - 2008, -13, null, - ], - [ - 38991, - 2008, -13, -30, - ], - [ - 38990, - 2008, -13, -31, - ], - [ - 39814, - 2008, 13, 1, - ], - [ - 39507, - 2007, 15, null, - ], - [ - 40210, - 2008, 26, 1, - ], - [ - 40199, - 2008, 26, -10, - ], - [ - 38686, - 2008, -26, 61, - ], - [ - 39641, - 2010, -15, -50, - ], - [ - 39741, - 2010, -15, 50, - ], - [ - 40552, - 2010, 15, -50, - ], - [ - 40652, - 2010, 15, 50, - ], - [ - 40179, - 2010, 1.5, 1, - ], - [ - 40178, - 2010, 1.5, 0, - ], - [ - 40148, - 2010, 0, 1.5, - ], - [ - 40179, - 2010, 1, 1.5, - ], - [ - 41075, - 2012, 6, 15, - ], - [ - 41060, - 2012, 6, null, - ], - [ - 40892, - 2012, null, 15, - ], - [ - 167, - null, 6, 15, - ], - [ - 3819, - 10, 6, 15, - ], - [ - 3622, - 10, null, null, - ], - [ - 274, - null, 10, null, - ], - [ - '#NUM!', - null, null, 10, - ], - [ - '#NUM!', - -20, null, null, - ], - [ - '#NUM!', - -20, 6, 15, - ], - 'Excel Maximum Date' => [ - 2958465, - 9999, 12, 31, - ], - 'Exceeded Excel Maximum Date' => [ - '#NUM!', - 10000, 1, 1, - ], - [ - 39670, - 2008, 8, 10, - ], - [ - 39813, - 2008, 12, 31, - ], - [ - 39692, - 2008, 8, 32, - ], - [ - 39844, - 2008, 13, 31, - ], - [ - 39813, - 2009, 1, 0, - ], - [ - 39812, - 2009, 1, -1, - ], - [ - 39782, - 2009, 0, 0, - ], - [ - 39781, - 2009, 0, -1, - ], - [ - 39752, - 2009, -1, 0, - ], - [ - 39751, - 2009, -1, -1, - ], - [ - 40146, - 2010, 0, -1, - ], - [ - 40329, - 2010, 5, 31, - ], + [6890, '18, 11, 11'], // year without centure + [1, '1900, 1, 1'], // Excel 1900 Calendar BaseDate + [59, '1900, 2, 28'], // Day before Excel mythical 1900 leap day + [60, '1900, 2, 29'], // Excel mythical 1900 leap day + [61, '1900, 3, 1'], // Day after Excel mythical 1900 leap day + [713, '1901, 12, 13'], // Day after actual 1904 leap day + [714, '1901, 12, 14'], // signed 32-bit Unix Timestamp Earliest Date + [1461, '1903, 12, 31'], // Day before Excel 1904 Calendar Base Date + [1462, '1904, 1, 1'], // Excel 1904 Calendar Base Date + [1463, '1904, 1, 2'], // Day after Excel 1904 Calendar Base Date + [22269, '1960, 12, 19'], + [25569, '1970, 1, 1'], // Unix Timestamp Base Date + [30292, '1982, 12, 7'], + [39611, '2008, 6, 12'], + [50424, '2038, 1, 19'], // 32-bit signed Unix Timestamp Latest Date + [50425, '2038, 1, 20'], // Day after 32-bit signed Unix Timestamp Latest Date + [39448, '2008, 1, 1'], + [39447, '2008, 1, Q15'], + [39446, '2008, 1, -1'], + [39417, '2008, 1, -30'], + [39416, '2008, 1, -31'], + [39082, '2008, 1, -365'], + [39508, '2008, 3, 1'], + [39507, '2008, 3, Q15'], + [39506, '2008, 3, -1'], + [39142, '2008, 3, -365'], + [39417, '2008, Q15, 1'], + [39387, '2008, -1, 1'], + [39083, '2008, -11, 1'], + [39052, '2008, -12, 1'], + [39022, '2008, -13, 1'], + [39051, '2008, -13, 30'], + [39021, '2008, -13, Q15'], + [38991, '2008, -13, -30'], + [38990, '2008, -13, -31'], + [39814, '2008, 13, 1'], + [39507, '2007, 15, Q15'], + [40210, '2008, 26, 1'], + [40199, '2008, 26, -10'], + [38686, '2008, -26, 61'], + [39641, '2010, -15, -50'], + [39741, '2010, -15, 50'], + [40552, '2010, 15, -50'], + [40652, '2010, 15, 50'], + [40179, '2010, 1.5, 1'], + [40178, '2010, 1.5, 0'], + [40148, '2010, 0, 1.5'], + [40179, '2010, 1, 1.5'], + [41075, '2012, 6, 15'], + [41060, '2012, 6, Q15'], + [40892, '2012, Q15, 15'], + [167, 'Q15, 6, 15'], + [3819, '10, 6, 15'], + [3622, '10, Q15, Q16'], + [274, 'Q14, 10, Q15'], + ['#NUM!', 'Q14, Q15, 10'], + ['#NUM!', '-20, Q14, Q15'], + ['#NUM!', '-20, 6, 15'], + [2958465, '9999, 12, 31'], // Excel maximum date + ['#NUM!', '10000, 1, 1'], // Exceeded Excel maximum date + [39670, '2008, 8, 10'], + [39813, '2008, 12, 31'], + [39692, '2008, 8, 32'], + [39844, '2008, 13, 31'], + [39813, '2009, 1, 0'], + [39812, '2009, 1, -1'], + [39782, '2009, 0, 0'], + [39781, '2009, 0, -1'], + [39752, '2009, -1, 0'], + [39751, '2009, -1, -1'], + [40146, '2010, 0, -1'], + [40329, '2010, 5, 31'], + [40199, '2010, 1, "21st"'], // Excel can't parse ordinal, PhpSpreadsheet can + [40258, '2010, "March", "21st"'], // ordinal and month name // MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date - [ - 40199, - 2010, 1, '21st', - ], - // MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date - [ - 40258, - 2010, 'March', '21st', - ], - // MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date - [ - 40258, - 2010, 'March', 21, - ], - [ - '#VALUE!', - 'ABC', 1, 21, - ], - [ - '#VALUE!', - 2010, 'DEF', 21, - ], - [ - '#VALUE!', - 2010, 3, 'GHI', - ], + [40258, '2010, "March", 21'], // Excel can't parse month name, PhpSpreadsheet can + ['#VALUE!', '"ABC", 1, 21'], + ['#VALUE!', '2010, "DEF", 21'], + ['#VALUE!', '2010, 3, "GHI"'], + ['exception', '2010, 3'], ]; diff --git a/tests/data/Calculation/DateTime/DATEDIF.php b/tests/data/Calculation/DateTime/DATEDIF.php index a6d2d761..5ba0bd3c 100644 --- a/tests/data/Calculation/DateTime/DATEDIF.php +++ b/tests/data/Calculation/DateTime/DATEDIF.php @@ -1,424 +1,112 @@ Date: Sun, 21 Mar 2021 21:40:49 +0100 Subject: [PATCH 129/187] Financial functions next stage of refactoring (#1943) * First steps splitting out the Amortization and Deprecation Excel functions from Financials * Verify which methods allow negative values for arguments * Additional unit tests for SLN() and SYD() * Additional unit tests for DDB() * Additional unit tests for DB() * Verify Amortization cases where salvage is greater than cost * More unit tests for Amortization * Resolve broken test in AMORLINC() and extract amortizationCoefficient calculation * verify amortizationCoefficient calculation * Extract YIELDDISC() and YIELDMAT() to Financial\Securities * Additional validation for Securities Yield functions --- .../Calculation/Calculation.php | 18 +- src/PhpSpreadsheet/Calculation/Financial.php | 337 ++++-------------- .../Calculation/Financial/Amortization.php | 163 +++++++++ .../Calculation/Financial/Depreciation.php | 287 +++++++++++++++ .../Financial/Securities/BaseValidations.php | 145 ++++++++ .../Financial/Securities/Constants.php | 10 + .../{Securities.php => Securities/Price.php} | 134 +------ .../Financial/Securities/Yields.php | 136 +++++++ .../data/Calculation/Financial/AMORDEGRC.php | 28 ++ tests/data/Calculation/Financial/AMORLINC.php | 16 +- tests/data/Calculation/Financial/DB.php | 121 ++++++- tests/data/Calculation/Financial/DDB.php | 113 ++++++ tests/data/Calculation/Financial/SLN.php | 34 +- tests/data/Calculation/Financial/SYD.php | 52 +++ .../data/Calculation/Financial/YIELDDISC.php | 24 ++ tests/data/Calculation/Financial/YIELDMAT.php | 28 ++ 16 files changed, 1225 insertions(+), 421 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Amortization.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Depreciation.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php rename src/PhpSpreadsheet/Calculation/Financial/{Securities.php => Securities/Price.php} (73%) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index dbea0850..9317699b 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -273,12 +273,12 @@ class Calculation ], 'AMORDEGRC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'AMORDEGRC'], + 'functionCall' => [Financial\Amortization::class, 'AMORDEGRC'], 'argumentCount' => '6,7', ], 'AMORLINC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'AMORLINC'], + 'functionCall' => [Financial\Amortization::class, 'AMORLINC'], 'argumentCount' => '6,7', ], 'AND' => [ @@ -1983,17 +1983,17 @@ class Calculation ], 'PRICE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial\Securities::class, 'price'], + 'functionCall' => [Financial\Securities\Price::class, 'price'], 'argumentCount' => '6,7', ], 'PRICEDISC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial\Securities::class, 'discounted'], + 'functionCall' => [Financial\Securities\Price::class, 'priceDiscounted'], 'argumentCount' => '4,5', ], 'PRICEMAT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial\Securities::class, 'maturity'], + 'functionCall' => [Financial\Securities\Price::class, 'priceAtMaturity'], 'argumentCount' => '5,6', ], 'PROB' => [ @@ -2225,7 +2225,7 @@ class Calculation ], 'SLN' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'SLN'], + 'functionCall' => [Financial\Depreciation::class, 'SLN'], 'argumentCount' => '3', ], 'SLOPE' => [ @@ -2356,7 +2356,7 @@ class Calculation ], 'SYD' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'SYD'], + 'functionCall' => [Financial\Depreciation::class, 'SYD'], 'argumentCount' => '4', ], 'T' => [ @@ -2641,12 +2641,12 @@ class Calculation ], 'YIELDDISC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'YIELDDISC'], + 'functionCall' => [Financial\Securities\Yields::class, 'yieldDiscounted'], 'argumentCount' => '4,5', ], 'YIELDMAT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'YIELDMAT'], + 'functionCall' => [Financial\Securities\Yields::class, 'yieldAtMaturity'], 'argumentCount' => '5,6', ], 'ZTEST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 9735e9f4..2b54e1cd 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -2,8 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Amortization; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Coupons; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Depreciation; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Dollar; use PhpOffice\PhpSpreadsheet\Calculation\Financial\InterestRate; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\TreasuryBill; class Financial { @@ -147,6 +152,10 @@ class Financial * Excel Function: * AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the AMORDEGRC() method in the Financial\Amortization class instead + * * @param float $cost The cost of the asset * @param mixed $purchased Date of the purchase of the asset * @param mixed $firstPeriod Date of the end of the first period @@ -164,57 +173,7 @@ class Financial */ public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0) { - $cost = Functions::flattenSingleValue($cost); - $purchased = Functions::flattenSingleValue($purchased); - $firstPeriod = Functions::flattenSingleValue($firstPeriod); - $salvage = Functions::flattenSingleValue($salvage); - $period = floor(Functions::flattenSingleValue($period)); - $rate = Functions::flattenSingleValue($rate); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - $yearFrac = DateTime::YEARFRAC($purchased, $firstPeriod, $basis); - if (is_string($yearFrac)) { - return $yearFrac; - } - - // The depreciation coefficients are: - // Life of assets (1/rate) Depreciation coefficient - // Less than 3 years 1 - // Between 3 and 4 years 1.5 - // Between 5 and 6 years 2 - // More than 6 years 2.5 - $fUsePer = 1.0 / $rate; - if ($fUsePer < 3.0) { - $amortiseCoeff = 1.0; - } elseif ($fUsePer < 5.0) { - $amortiseCoeff = 1.5; - } elseif ($fUsePer <= 6.0) { - $amortiseCoeff = 2.0; - } else { - $amortiseCoeff = 2.5; - } - - $rate *= $amortiseCoeff; - $fNRate = round($yearFrac * $rate * $cost, 0); - $cost -= $fNRate; - $fRest = $cost - $salvage; - - for ($n = 0; $n < $period; ++$n) { - $fNRate = round($rate * $cost, 0); - $fRest -= $fNRate; - - if ($fRest < 0.0) { - switch ($period - $n) { - case 0: - case 1: - return round($cost * 0.5, 0); - default: - return 0.0; - } - } - $cost -= $fNRate; - } - - return $fNRate; + return Amortization::AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis); } /** @@ -227,6 +186,10 @@ class Financial * Excel Function: * AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis]) * + * @Deprecated 1.18.0 + * + * @see Use the AMORLINC() method in the Financial\Amortization class instead + * * @param float $cost The cost of the asset * @param mixed $purchased Date of the purchase of the asset * @param mixed $firstPeriod Date of the end of the first period @@ -244,39 +207,7 @@ class Financial */ public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0) { - $cost = Functions::flattenSingleValue($cost); - $purchased = Functions::flattenSingleValue($purchased); - $firstPeriod = Functions::flattenSingleValue($firstPeriod); - $salvage = Functions::flattenSingleValue($salvage); - $period = Functions::flattenSingleValue($period); - $rate = Functions::flattenSingleValue($rate); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - - $fOneRate = $cost * $rate; - $fCostDelta = $cost - $salvage; - // Note, quirky variation for leap years on the YEARFRAC for this function - $purchasedYear = DateTime::YEAR($purchased); - $yearFrac = DateTime::YEARFRAC($purchased, $firstPeriod, $basis); - if (is_string($yearFrac)) { - return $yearFrac; - } - - if (($basis == 1) && ($yearFrac < 1) && (DateTime::isLeapYear($purchasedYear))) { - $yearFrac *= 365 / 366; - } - - $f0Rate = $yearFrac * $rate * $cost; - $nNumOfFullPeriods = (int) (($cost - $salvage - $f0Rate) / $fOneRate); - - if ($period == 0) { - return $f0Rate; - } elseif ($period <= $nNumOfFullPeriods) { - return $fOneRate; - } elseif ($period == ($nNumOfFullPeriods + 1)) { - return $fCostDelta - $fOneRate * $nNumOfFullPeriods - $f0Rate; - } - - return 0.0; + return Amortization::AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis); } /** @@ -613,6 +544,10 @@ class Financial * Excel Function: * DB(cost,salvage,life,period[,month]) * + * @Deprecated 1.18.0 + * + * @see Use the DB() method in the Financial\Depreciation class instead + * * @param float $cost Initial cost of the asset * @param float $salvage Value at the end of the depreciation. * (Sometimes called the salvage value of the asset) @@ -627,46 +562,7 @@ class Financial */ public static function DB($cost, $salvage, $life, $period, $month = 12) { - $cost = Functions::flattenSingleValue($cost); - $salvage = Functions::flattenSingleValue($salvage); - $life = Functions::flattenSingleValue($life); - $period = Functions::flattenSingleValue($period); - $month = Functions::flattenSingleValue($month); - - // Validate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($month))) { - $cost = (float) $cost; - $salvage = (float) $salvage; - $life = (int) $life; - $period = (int) $period; - $month = (int) $month; - if ($cost == 0) { - return 0.0; - } elseif (($cost < 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($month < 1)) { - return Functions::NAN(); - } - // Set Fixed Depreciation Rate - $fixedDepreciationRate = 1 - ($salvage / $cost) ** (1 / $life); - $fixedDepreciationRate = round($fixedDepreciationRate, 3); - - // Loop through each period calculating the depreciation - $previousDepreciation = 0; - $depreciation = 0; - for ($per = 1; $per <= $period; ++$per) { - if ($per == 1) { - $depreciation = $cost * $fixedDepreciationRate * $month / 12; - } elseif ($per == ($life + 1)) { - $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12; - } else { - $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate; - } - $previousDepreciation += $depreciation; - } - - return $depreciation; - } - - return Functions::VALUE(); + return Depreciation::DB($cost, $salvage, $life, $period, $month); } /** @@ -678,6 +574,10 @@ class Financial * Excel Function: * DDB(cost,salvage,life,period[,factor]) * + * @Deprecated 1.18.0 + * + * @see Use the DDB() method in the Financial\Depreciation class instead + * * @param float $cost Initial cost of the asset * @param float $salvage Value at the end of the depreciation. * (Sometimes called the salvage value of the asset) @@ -693,38 +593,7 @@ class Financial */ public static function DDB($cost, $salvage, $life, $period, $factor = 2.0) { - $cost = Functions::flattenSingleValue($cost); - $salvage = Functions::flattenSingleValue($salvage); - $life = Functions::flattenSingleValue($life); - $period = Functions::flattenSingleValue($period); - $factor = Functions::flattenSingleValue($factor); - - // Validate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period)) && (is_numeric($factor))) { - $cost = (float) $cost; - $salvage = (float) $salvage; - $life = (int) $life; - $period = (int) $period; - $factor = (float) $factor; - if (($cost <= 0) || (($salvage / $cost) < 0) || ($life <= 0) || ($period < 1) || ($factor <= 0.0) || ($period > $life)) { - return Functions::NAN(); - } - // Set Fixed Depreciation Rate - $fixedDepreciationRate = 1 - ($salvage / $cost) ** (1 / $life); - $fixedDepreciationRate = round($fixedDepreciationRate, 3); - - // Loop through each period calculating the depreciation - $previousDepreciation = 0; - $depreciation = 0; - for ($per = 1; $per <= $period; ++$per) { - $depreciation = min(($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation)); - $previousDepreciation += $depreciation; - } - - return $depreciation; - } - - return Functions::VALUE(); + return Depreciation::DDB($cost, $salvage, $life, $period, $factor); } /** @@ -800,7 +669,7 @@ class Financial */ public static function DOLLARDE($fractional_dollar = null, $fraction = 0) { - return Financial\Dollar::decimal($fractional_dollar, $fraction); + return Dollar::decimal($fractional_dollar, $fraction); } /** @@ -824,7 +693,7 @@ class Financial */ public static function DOLLARFR($decimal_dollar = null, $fraction = 0) { - return Financial\Dollar::fractional($decimal_dollar, $fraction); + return Dollar::fractional($decimal_dollar, $fraction); } /** @@ -1368,7 +1237,7 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the price() method in the Financial\Securities class instead + * @see Use the price() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date when the security @@ -1393,7 +1262,7 @@ class Financial */ public static function PRICE($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis = 0) { - return Financial\Securities::price($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis); + return Securities\Price::price($settlement, $maturity, $rate, $yield, $redemption, $frequency, $basis); } /** @@ -1403,12 +1272,13 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the discounted() method in the Financial\Securities class instead + * @see Use the priceDiscounted() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. + * The security settlement date is the date after the issue 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. + * The maturity date is the date when the security expires. * @param int $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. @@ -1422,7 +1292,7 @@ class Financial */ public static function PRICEDISC($settlement, $maturity, $discount, $redemption, $basis = 0) { - return Financial\Securities::discounted($settlement, $maturity, $discount, $redemption, $basis); + return Securities\Price::priceDiscounted($settlement, $maturity, $discount, $redemption, $basis); } /** @@ -1432,12 +1302,13 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the maturity() method in the Financial\Securities class instead + * @see Use the priceAtMaturity() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. - * The security's settlement date is the date after the issue date when the security is traded to the buyer. + * The security's settlement date is the date after the issue 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. + * 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 @@ -1452,7 +1323,7 @@ class Financial */ public static function PRICEMAT($settlement, $maturity, $issue, $rate, $yield, $basis = 0) { - return Financial\Securities::maturity($settlement, $maturity, $issue, $rate, $yield, $basis); + return Securities\Price::priceAtMaturity($settlement, $maturity, $issue, $rate, $yield, $basis); } /** @@ -1640,6 +1511,10 @@ class Financial * * Returns the straight-line depreciation of an asset for one period * + * @Deprecated 1.18.0 + * + * @see Use the SLN() method in the Financial\Depreciation class instead + * * @param mixed $cost Initial cost of the asset * @param mixed $salvage Value at the end of the depreciation * @param mixed $life Number of periods over which the asset is depreciated @@ -1648,20 +1523,7 @@ class Financial */ public static function SLN($cost, $salvage, $life) { - $cost = Functions::flattenSingleValue($cost); - $salvage = Functions::flattenSingleValue($salvage); - $life = Functions::flattenSingleValue($life); - - // Calculate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life))) { - if ($life < 0) { - return Functions::NAN(); - } - - return ($cost - $salvage) / $life; - } - - return Functions::VALUE(); + return Depreciation::SLN($cost, $salvage, $life); } /** @@ -1669,6 +1531,10 @@ class Financial * * Returns the sum-of-years' digits depreciation of an asset for a specified period. * + * @Deprecated 1.18.0 + * + * @see Use the SYD() method in the Financial\Depreciation class instead + * * @param mixed $cost Initial cost of the asset * @param mixed $salvage Value at the end of the depreciation * @param mixed $life Number of periods over which the asset is depreciated @@ -1678,21 +1544,7 @@ class Financial */ public static function SYD($cost, $salvage, $life, $period) { - $cost = Functions::flattenSingleValue($cost); - $salvage = Functions::flattenSingleValue($salvage); - $life = Functions::flattenSingleValue($life); - $period = Functions::flattenSingleValue($period); - - // Calculate - if ((is_numeric($cost)) && (is_numeric($salvage)) && (is_numeric($life)) && (is_numeric($period))) { - if (($life < 1) || ($period > $life)) { - return Functions::NAN(); - } - - return (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1)); - } - - return Functions::VALUE(); + return Depreciation::SYD($cost, $salvage, $life, $period); } /** @@ -1714,7 +1566,7 @@ class Financial */ public static function TBILLEQ($settlement, $maturity, $discount) { - return Financial\TreasuryBill::bondEquivalentYield($settlement, $maturity, $discount); + return TreasuryBill::bondEquivalentYield($settlement, $maturity, $discount); } /** @@ -1737,7 +1589,7 @@ class Financial */ public static function TBILLPRICE($settlement, $maturity, $discount) { - return Financial\TreasuryBill::price($settlement, $maturity, $discount); + return TreasuryBill::price($settlement, $maturity, $discount); } /** @@ -1760,7 +1612,7 @@ class Financial */ public static function TBILLYIELD($settlement, $maturity, $price) { - return Financial\TreasuryBill::yield($settlement, $maturity, $price); + return TreasuryBill::yield($settlement, $maturity, $price); } private static function bothNegAndPos($neg, $pos) @@ -1977,10 +1829,13 @@ class Financial * * Returns the annual yield of a security that pays interest at maturity. * + * @see Use the yieldDiscounted() method in the Financial\Securities\Yields class instead + * * @param mixed $settlement The security's settlement date. - * The security's settlement date is the date after the issue date when the security is traded to the buyer. + * The security's settlement date is the date after the issue 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. + * The maturity date is the date when the security expires. * @param int $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. @@ -1994,32 +1849,7 @@ class Financial */ public static function YIELDDISC($settlement, $maturity, $price, $redemption, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $price = Functions::flattenSingleValue($price); - $redemption = Functions::flattenSingleValue($redemption); - $basis = (int) Functions::flattenSingleValue($basis); - - // Validate - if (is_numeric($price) && is_numeric($redemption)) { - if (($price <= 0) || ($redemption <= 0)) { - return Functions::NAN(); - } - $daysPerYear = Financial\Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); - if (!is_numeric($daysPerYear)) { - return $daysPerYear; - } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - $daysBetweenSettlementAndMaturity *= $daysPerYear; - - return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity); - } - - return Functions::VALUE(); + return Securities\Yields::yieldDiscounted($settlement, $maturity, $price, $redemption, $basis); } /** @@ -2027,10 +1857,15 @@ class Financial * * Returns the annual yield of a security that pays interest at maturity. * + * @Deprecated 1.18.0 + * + * @see Use the yieldAtMaturity() method in the Financial\Securities\Yields class instead + * * @param mixed $settlement The security's settlement date. - * The security's settlement date is the date after the issue date when the security is traded to the buyer. + * The security's settlement date is the date after the issue 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. + * 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 @@ -2045,46 +1880,6 @@ class Financial */ public static function YIELDMAT($settlement, $maturity, $issue, $rate, $price, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $issue = Functions::flattenSingleValue($issue); - $rate = Functions::flattenSingleValue($rate); - $price = Functions::flattenSingleValue($price); - $basis = (int) Functions::flattenSingleValue($basis); - - // Validate - if (is_numeric($rate) && is_numeric($price)) { - if (($rate <= 0) || ($price <= 0)) { - return Functions::NAN(); - } - $daysPerYear = Financial\Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); - if (!is_numeric($daysPerYear)) { - return $daysPerYear; - } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - // return date error - return $daysBetweenIssueAndSettlement; - } - $daysBetweenIssueAndSettlement *= $daysPerYear; - $daysBetweenIssueAndMaturity = DateTime::YEARFRAC($issue, $maturity, $basis); - if (!is_numeric($daysBetweenIssueAndMaturity)) { - // return date error - return $daysBetweenIssueAndMaturity; - } - $daysBetweenIssueAndMaturity *= $daysPerYear; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - $daysBetweenSettlementAndMaturity *= $daysPerYear; - - return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) * - ($daysPerYear / $daysBetweenSettlementAndMaturity); - } - - return Functions::VALUE(); + return Securities\Yields::yieldAtMaturity($settlement, $maturity, $issue, $rate, $price, $basis); } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php new file mode 100644 index 00000000..76be7e12 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php @@ -0,0 +1,163 @@ +getMessage(); + } + + if ($cost === 0.0) { + return 0.0; + } + + // Set Fixed Depreciation Rate + $fixedDepreciationRate = 1 - ($salvage / $cost) ** (1 / $life); + $fixedDepreciationRate = round($fixedDepreciationRate, 3); + + // Loop through each period calculating the depreciation + // TODO Handle period value between 0 and 1 (e.g. 0.5) + $previousDepreciation = 0; + $depreciation = 0; + for ($per = 1; $per <= $period; ++$per) { + if ($per == 1) { + $depreciation = $cost * $fixedDepreciationRate * $month / 12; + } elseif ($per == ($life + 1)) { + $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate * (12 - $month) / 12; + } else { + $depreciation = ($cost - $previousDepreciation) * $fixedDepreciationRate; + } + $previousDepreciation += $depreciation; + } + + return $depreciation; + } + + /** + * DDB. + * + * Returns the depreciation of an asset for a specified period using the + * double-declining balance method or some other method you specify. + * + * Excel Function: + * DDB(cost,salvage,life,period[,factor]) + * + * @param float $cost Initial cost of the asset + * @param float $salvage Value at the end of the depreciation. + * (Sometimes called the salvage value of the asset) + * @param int $life Number of periods over which the asset is depreciated. + * (Sometimes called the useful life of the asset) + * @param int $period The period for which you want to calculate the + * depreciation. Period must use the same units as life. + * @param float $factor The rate at which the balance declines. + * If factor is omitted, it is assumed to be 2 (the + * double-declining balance method). + * + * @return float|string + */ + public static function DDB($cost, $salvage, $life, $period, $factor = 2.0) + { + $cost = Functions::flattenSingleValue($cost); + $salvage = Functions::flattenSingleValue($salvage); + $life = Functions::flattenSingleValue($life); + $period = Functions::flattenSingleValue($period); + $factor = Functions::flattenSingleValue($factor); + + try { + $cost = self::validateCost($cost); + $salvage = self::validateSalvage($salvage); + $life = self::validateLife($life); + $period = self::validatePeriod($period); + $factor = self::validateFactor($factor); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($period > $life) { + return Functions::NAN(); + } + + // Loop through each period calculating the depreciation + // TODO Handling for fractional $period values + $previousDepreciation = 0; + $depreciation = 0; + for ($per = 1; $per <= $period; ++$per) { + $depreciation = min(($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation)); + $previousDepreciation += $depreciation; + } + + return $depreciation; + } + + /** + * SLN. + * + * Returns the straight-line depreciation of an asset for one period + * + * @param mixed $cost Initial cost of the asset + * @param mixed $salvage Value at the end of the depreciation + * @param mixed $life Number of periods over which the asset is depreciated + * + * @return float|string Result, or a string containing an error + */ + public static function SLN($cost, $salvage, $life) + { + $cost = Functions::flattenSingleValue($cost); + $salvage = Functions::flattenSingleValue($salvage); + $life = Functions::flattenSingleValue($life); + + try { + $cost = self::validateCost($cost, true); + $salvage = self::validateSalvage($salvage, true); + $life = self::validateLife($life, true); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($life === 0.0) { + return Functions::DIV0(); + } + + return ($cost - $salvage) / $life; + } + + /** + * SYD. + * + * Returns the sum-of-years' digits depreciation of an asset for a specified period. + * + * @param mixed $cost Initial cost of the asset + * @param mixed $salvage Value at the end of the depreciation + * @param mixed $life Number of periods over which the asset is depreciated + * @param mixed $period Period + * + * @return float|string Result, or a string containing an error + */ + public static function SYD($cost, $salvage, $life, $period) + { + $cost = Functions::flattenSingleValue($cost); + $salvage = Functions::flattenSingleValue($salvage); + $life = Functions::flattenSingleValue($life); + $period = Functions::flattenSingleValue($period); + + try { + $cost = self::validateCost($cost, true); + $salvage = self::validateSalvage($salvage); + $life = self::validateLife($life); + $period = self::validatePeriod($period); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($period > $life) { + return Functions::NAN(); + } + + $syd = (($cost - $salvage) * ($life - $period + 1) * 2) / ($life * ($life + 1)); + + return $syd; + } + + private static function validateCost($cost, bool $negativeValueAllowed = false): float + { + if (!is_numeric($cost)) { + throw new Exception(Functions::VALUE()); + } + + $cost = (float) $cost; + if ($cost < 0.0 && $negativeValueAllowed === false) { + throw new Exception(Functions::NAN()); + } + + return $cost; + } + + private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float + { + if (!is_numeric($salvage)) { + throw new Exception(Functions::VALUE()); + } + + $salvage = (float) $salvage; + if ($salvage < 0.0 && $negativeValueAllowed === false) { + throw new Exception(Functions::NAN()); + } + + return $salvage; + } + + private static function validateLife($life, bool $negativeValueAllowed = false): float + { + if (!is_numeric($life)) { + throw new Exception(Functions::VALUE()); + } + + $life = (float) $life; + if ($life < 0.0 && $negativeValueAllowed === false) { + throw new Exception(Functions::NAN()); + } + + return $life; + } + + private static function validatePeriod($period, bool $negativeValueAllowed = false): float + { + if (!is_numeric($period)) { + throw new Exception(Functions::VALUE()); + } + + $period = (float) $period; + if ($period <= 0.0 && $negativeValueAllowed === false) { + throw new Exception(Functions::NAN()); + } + + return $period; + } + + private static function validateMonth($month): int + { + if (!is_numeric($month)) { + throw new Exception(Functions::VALUE()); + } + + $month = (int) $month; + if ($month < 1) { + throw new Exception(Functions::NAN()); + } + + return $month; + } + + private static function validateFactor($factor): float + { + if (!is_numeric($factor)) { + throw new Exception(Functions::VALUE()); + } + + $factor = (float) $factor; + if ($factor <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $factor; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php new file mode 100644 index 00000000..88cb8660 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php @@ -0,0 +1,145 @@ += $maturity) { + throw new Exception(Functions::NAN()); + } + } + + protected static function validateRate($rate): float + { + if (!is_numeric($rate)) { + throw new Exception(Functions::VALUE()); + } + + $rate = (float) $rate; + if ($rate < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $rate; + } + + protected static function validatePrice($price): float + { + if (!is_numeric($price)) { + throw new Exception(Functions::VALUE()); + } + + $price = (float) $price; + if ($price < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $price; + } + + protected static function validateYield($yield): float + { + if (!is_numeric($yield)) { + throw new Exception(Functions::VALUE()); + } + + $yield = (float) $yield; + if ($yield < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $yield; + } + + protected static function validateRedemption($redemption): float + { + if (!is_numeric($redemption)) { + throw new Exception(Functions::VALUE()); + } + + $redemption = (float) $redemption; + if ($redemption <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $redemption; + } + + protected static function validateDiscount($discount): float + { + if (!is_numeric($discount)) { + throw new Exception(Functions::VALUE()); + } + + $discount = (float) $discount; + if ($discount <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $discount; + } + + protected static function validateFrequency($frequency): int + { + if (!is_numeric($frequency)) { + throw new Exception(Functions::VALUE()); + } + + $frequency = (int) $frequency; + if ( + ($frequency !== SecuritiesConstants::FREQUENCY_ANNUAL) && + ($frequency !== SecuritiesConstants::FREQUENCY_SEMI_ANNUAL) && + ($frequency !== SecuritiesConstants::FREQUENCY_QUARTERLY) + ) { + throw new Exception(Functions::NAN()); + } + + return $frequency; + } + + protected static function validateBasis($basis): int + { + if (!is_numeric($basis)) { + throw new Exception(Functions::VALUE()); + } + + $basis = (int) $basis; + if (($basis < 0) || ($basis > 4)) { + throw new Exception(Functions::NAN()); + } + + return $basis; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php new file mode 100644 index 00000000..ba9d2389 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php @@ -0,0 +1,10 @@ += $maturity) { - throw new Exception(Functions::NAN()); - } - } - - private static function validateRate($rate): float - { - if (!is_numeric($rate)) { - throw new Exception(Functions::VALUE()); - } - - $rate = (float) $rate; - if ($rate < 0.0) { - throw new Exception(Functions::NAN()); - } - - return $rate; - } - - private static function validateYield($yield): float - { - if (!is_numeric($yield)) { - throw new Exception(Functions::VALUE()); - } - - $yield = (float) $yield; - if ($yield < 0.0) { - throw new Exception(Functions::NAN()); - } - - return $yield; - } - - private static function validateRedemption($redemption): float - { - if (!is_numeric($redemption)) { - throw new Exception(Functions::VALUE()); - } - - $redemption = (float) $redemption; - if ($redemption <= 0.0) { - throw new Exception(Functions::NAN()); - } - - return $redemption; - } - - private static function validateDiscount($discount): float - { - if (!is_numeric($discount)) { - throw new Exception(Functions::VALUE()); - } - - $discount = (float) $discount; - if ($discount <= 0.0) { - throw new Exception(Functions::NAN()); - } - - return $discount; - } - - private static function validateFrequency($frequency): int - { - if (!is_numeric($frequency)) { - throw new Exception(Functions::VALUE()); - } - - $frequency = (int) $frequency; - if ( - ($frequency !== self::FREQUENCY_ANNUAL) && - ($frequency !== self::FREQUENCY_SEMI_ANNUAL) && - ($frequency !== self::FREQUENCY_QUARTERLY) - ) { - throw new Exception(Functions::NAN()); - } - - return $frequency; - } - - private static function validateBasis($basis): int - { - if (!is_numeric($basis)) { - throw new Exception(Functions::VALUE()); - } - - $basis = (int) $basis; - if (($basis < 0) || ($basis > 4)) { - throw new Exception(Functions::NAN()); - } - - return $basis; - } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php new file mode 100644 index 00000000..0918d637 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php @@ -0,0 +1,136 @@ +getMessage(); + } + + $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + if (!is_numeric($daysPerYear)) { + return $daysPerYear; + } + $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + $daysBetweenSettlementAndMaturity *= $daysPerYear; + + return (($redemption - $price) / $price) * ($daysPerYear / $daysBetweenSettlementAndMaturity); + } + + /** + * YIELDMAT. + * + * Returns the annual yield of a security that pays interest at maturity. + * + * @param mixed $settlement The security's settlement date. + * The security's settlement date is the date after the issue 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 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 int $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string Result, or a string containing an error + */ + public static function yieldAtMaturity($settlement, $maturity, $issue, $rate, $price, $basis = 0) + { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $issue = Functions::flattenSingleValue($issue); + $rate = Functions::flattenSingleValue($rate); + $price = Functions::flattenSingleValue($price); + $basis = Functions::flattenSingleValue($basis); + + try { + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); + self::validateSecurityPeriod($settlement, $maturity); + $issue = self::validateIssueDate($issue); + $rate = self::validateRate($rate); + $price = self::validatePrice($price); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + if (!is_numeric($daysPerYear)) { + return $daysPerYear; + } + $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + $daysBetweenIssueAndSettlement *= $daysPerYear; + $daysBetweenIssueAndMaturity = DateTime::YEARFRAC($issue, $maturity, $basis); + if (!is_numeric($daysBetweenIssueAndMaturity)) { + // return date error + return $daysBetweenIssueAndMaturity; + } + $daysBetweenIssueAndMaturity *= $daysPerYear; + $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + $daysBetweenSettlementAndMaturity *= $daysPerYear; + + return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / + (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) * + ($daysPerYear / $daysBetweenSettlementAndMaturity); + } +} diff --git a/tests/data/Calculation/Financial/AMORDEGRC.php b/tests/data/Calculation/Financial/AMORDEGRC.php index 59549e78..f4007033 100644 --- a/tests/data/Calculation/Financial/AMORDEGRC.php +++ b/tests/data/Calculation/Financial/AMORDEGRC.php @@ -7,6 +7,30 @@ return [ 776, 2400, '2008-08-19', '2008-12-31', 300, 1, 0.15, 1, ], + [ + 820, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.2, 1, + ], + [ + 492, + 2400, '2008-08-19', '2008-12-31', 300, 2, 0.2, 1, + ], + [ + 886, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.22, 1, + ], + [ + 949, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.24, 1, + ], + [ + 494, + 2400, '2008-08-19', '2008-12-31', 300, 2, 0.24, 1, + ], + [ + 902, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.3, 1, + ], [ 42, 150, '2011-01-01', '2011-09-30', 20, 1, 0.2, 4, @@ -27,4 +51,8 @@ return [ '#VALUE!', 550, 'notADate', '2020-12-25', 20, 1, 0.2, 4, ], + [ + '#VALUE!', + 550, '2011-01-01', 'notADate', 20, 1, 0.2, 4, + ], ]; diff --git a/tests/data/Calculation/Financial/AMORLINC.php b/tests/data/Calculation/Financial/AMORLINC.php index 46f19332..34485c8a 100644 --- a/tests/data/Calculation/Financial/AMORLINC.php +++ b/tests/data/Calculation/Financial/AMORLINC.php @@ -5,26 +5,30 @@ return [ [ 360, - 2400, '2008-08-19', '2008-12-31', 300, 1, 0.14999999999999999, 1, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.15, 1, + ], + [ + 576, + 2400, '2008-08-19', '2008-12-31', 300, 2, 0.24, 1, ], [ 30, - 150, '2011-01-01', '2011-09-30', 20, 1, 0.20000000000000001, 4, + 150, '2011-01-01', '2011-09-30', 20, 1, 0.2, 4, ], [ 22.41666667, - 150, '2011-01-01', '2011-09-30', 20, 0, 0.20000000000000001, 4, + 150, '2011-01-01', '2011-09-30', 20, 0, 0.2, 4, ], [ 17.58333333, - 150, '2011-01-01', '2011-09-30', 20, 4, 0.20000000000000001, 4, + 150, '2011-01-01', '2011-09-30', 20, 4, 0.2, 4, ], [ 0.0, - 150, '2011-01-01', '2011-09-30', 20, 5, 0.20000000000000001, 4, + 150, '2011-01-01', '2011-09-30', 20, 5, 0.2, 4, ], [ '#VALUE!', - 150, 'notADate', '2011-09-30', 20, 1, 0.20000000000000001, 4, + 150, 'notADate', '2011-09-30', 20, 1, 0.2, 4, ], ]; diff --git a/tests/data/Calculation/Financial/DB.php b/tests/data/Calculation/Financial/DB.php index 7f8fc6fa..89bd22f2 100644 --- a/tests/data/Calculation/Financial/DB.php +++ b/tests/data/Calculation/Financial/DB.php @@ -115,6 +115,47 @@ return [ 6, 6, ], + [ + 4651.199, + 12000, + 2000, + 3.5, + 2, + 1, + ], + [ + 3521.399, + 12000, + 2000, + 5, + 2.5, + 1, + ], + [ + 3521.399, + 12000, + 2000, + 5, + 2.5, + 1.2, + ], + // Period value between 0 and 1 not yet handled in code + // [ + // 301.0, + // 12000, + // 2000, + // 5, + // 0.5, + // 1, + // ], + [ + -554.116, + 12000, + 15000, + 5, + 2, + 1, + ], [ '#NUM!', -1000, @@ -125,10 +166,82 @@ return [ ], [ '#VALUE!', - 'ABC', - 100, + 'Invalid', + 1000, 5, - 6, - 6, + 2, + 1, + ], + [ + '#VALUE!', + 12000, + 'Invalid', + 5, + 2, + 1, + ], + [ + '#VALUE!', + 12000, + 1000, + 'Invalid', + 2, + 1, + ], + [ + '#VALUE!', + 12000, + 1000, + 5, + 'Invalid', + 1, + ], + [ + '#VALUE!', + 12000, + 1000, + 5, + 2, + 'Invalid', + ], + [ + '#NUM!', + -12000, + 1000, + 5, + 2, + 1, + ], + [ + '#NUM!', + 12000, + -1000, + 5, + 2, + 1, + ], + [ + '#NUM!', + 12000, + 1000, + 5, + 0, + 1, + ], + [ + '#NUM!', + 12000, + 1000, + 5, + -2, + 1, + ], + [ + '#NUM!', + 12000, + 1000, + 5, + 2, + 0, ], ]; diff --git a/tests/data/Calculation/Financial/DDB.php b/tests/data/Calculation/Financial/DDB.php index 879224ca..67962ea2 100644 --- a/tests/data/Calculation/Financial/DDB.php +++ b/tests/data/Calculation/Financial/DDB.php @@ -98,6 +98,47 @@ return [ 5, 5, ], + [ + 972.0, + 12000, + 1000, + 5, + 3, + 0.5, + ], + [ + 1259.4752186588921, + 12000, + 1000, + 3.5, + 3, + 0.5, + ], + [ + 1080.00, + 12000, + 1000, + 5, + 2, + 0.5, + ], + [ + 0.0, + 12000, + 15000, + 5, + 2, + 0.5, + ], + // Code does not yet handle fractional period values for DDB, only integer + // [ + // 1024.58, + // 12000, + // 1000, + // 5, + // 2.5, + // 0.5, + // ], [ '#NUM!', -2400, @@ -112,4 +153,76 @@ return [ 36500, 1, ], + [ + '#VALUE!', + 12000, + 'INVALID', + 5, + 3, + 0.5, + ], + [ + '#VALUE!', + 12000, + 1000, + 'INVALID', + 3, + 0.5, + ], + [ + '#VALUE!', + 12000, + 1000, + 5, + 'INVALID', + 0.5, + ], + [ + '#VALUE!', + 12000, + 1000, + 5, + 3, + 'INVALID', + ], + [ + '#NUM!', + 12000, + -1000, + 5, + 3, + 0.5, + ], + [ + '#NUM!', + 12000, + 1000, + 5, + -3, + 0.5, + ], + [ + '#NUM!', + 12000, + 1000, + 5, + 3, + -0.5, + ], + [ + '#NUM!', + 12000, + 1000, + 5, + 0, + 0.5, + ], + [ + '#NUM!', + 12000, + 1000, + 2, + 3, + 0.5, + ], ]; diff --git a/tests/data/Calculation/Financial/SLN.php b/tests/data/Calculation/Financial/SLN.php index 5dcf9eda..f63120c1 100644 --- a/tests/data/Calculation/Financial/SLN.php +++ b/tests/data/Calculation/Financial/SLN.php @@ -30,11 +30,39 @@ return [ [45000, 7500, 10], ], [ - '#NUM!', - [10000, 1000, -1], + -10500, + [12000, 1500, -1], + ], + [ + 21000, + [12000, 1500, 0.5], + ], + [ + 3250, + [12000, -1000, 4], + ], + [ + -250, + [0, 1000, 4], + ], + [ + -600, + [12000, 15000, 5], + ], + [ + '#DIV/0!', + [12000, 1500, 0], ], [ '#VALUE!', - ['INVALID', 1000, -1], + ['INVALID', 1000, 1], + ], + [ + '#VALUE!', + [12000, 'INVALID', 1], + ], + [ + '#VALUE!', + [12000, 1000, 'INVALID'], ], ]; diff --git a/tests/data/Calculation/Financial/SYD.php b/tests/data/Calculation/Financial/SYD.php index e6b612b6..a8dd078c 100644 --- a/tests/data/Calculation/Financial/SYD.php +++ b/tests/data/Calculation/Financial/SYD.php @@ -33,6 +33,30 @@ return [ 409.09090909090907, [30000, 7500, 10, 10], ], + [ + -800, + [-2000, 1000, 5, 2], + ], + [ + 3771.4285714285716, + [12000, 1000, 2.5, 2], + ], + [ + 5028.571428571428, + [12000, 1000, 2.5, 1.5], + ], + [ + -600, + [-2000, 1000, 5, 3], + ], + [ + -800, + [12000, 15000, 5, 2], + ], + [ + '#NUM!', + [12000, -1000, 5, 3], + ], [ '#NUM!', [10000, 1000, 5, 10], @@ -41,4 +65,32 @@ return [ '#VALUE!', ['INVALID', 1000, 5, 1], ], + [ + '#VALUE!', + [12000, 'INVALID', 5, 1], + ], + [ + '#VALUE!', + [12000, 1000, 'INVALID', 1], + ], + [ + '#VALUE!', + [12000, 1000, 5, 'INVALID'], + ], + [ + '#NUM!', + [12000, -1, 5, 2], + ], + [ + '#NUM!', + [12000, 1000, -5, 1], + ], + [ + '#NUM!', + [12000, 1000, 5, 0], + ], + [ + '#NUM!', + [12000, 1000, 5, -1], + ], ]; diff --git a/tests/data/Calculation/Financial/YIELDDISC.php b/tests/data/Calculation/Financial/YIELDDISC.php index e6260a86..8750e98a 100644 --- a/tests/data/Calculation/Financial/YIELDDISC.php +++ b/tests/data/Calculation/Financial/YIELDDISC.php @@ -9,4 +9,28 @@ return [ 0.06220123250590336, '1-Jan-2017', '30-Jun-2017', 97, 100, ], + [ + '#VALUE!', + 'Invalid', '30-Jun-2017', 97, 100, + ], + [ + '#VALUE!', + '1-Jan-2017', 'Invalid', 97, 100, + ], + [ + '#VALUE!', + '1-Jan-2017', '30-Jun-2017', 'NaN', 100, + ], + [ + '#VALUE!', + '1-Jan-2017', '30-Jun-2017', 97, 'NaN', + ], + [ + '#NUM!', + '1-Jan-2017', '30-Jun-2017', -97, 100, + ], + [ + '#NUM!', + '1-Jan-2017', '30-Jun-2017', 97, -100, + ], ]; diff --git a/tests/data/Calculation/Financial/YIELDMAT.php b/tests/data/Calculation/Financial/YIELDMAT.php index 6f26b15c..49ced033 100644 --- a/tests/data/Calculation/Financial/YIELDMAT.php +++ b/tests/data/Calculation/Financial/YIELDMAT.php @@ -9,4 +9,32 @@ return [ 0.04210977320221025, '1-Jan-2017', '30-Jun-2018', '01-Jul-2014', 0.055, 101, ], + [ + '#VALUE!', + 'Invalid', '30-Jun-2018', '01-Jul-2014', 0.055, 101, + ], + [ + '#VALUE!', + '1-Jan-2017', 'Invalid', '01-Jul-2014', 0.055, 101, + ], + [ + '#VALUE!', + '1-Jan-2017', '30-Jun-2018', 'Invalid', 0.055, 101, + ], + [ + '#VALUE!', + '1-Jan-2017', '30-Jun-2018', '01-Jul-2014', 'NaN', 101, + ], + [ + '#VALUE!', + '1-Jan-2017', '30-Jun-2018', '01-Jul-2014', 0.055, 'NaN', + ], + [ + '#NUM!', + '1-Jan-2017', '30-Jun-2018', '01-Jul-2014', -0.055, 101, + ], + [ + '#NUM!', + '1-Jan-2017', '30-Jun-2018', '01-Jul-2014', 0.055, -101, + ], ]; From 1a7b9a446abab5499bbcdd96349663b6a819909d Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 23 Mar 2021 13:34:28 +0100 Subject: [PATCH 130/187] First phase of refactoring the Excel Text functions (#1945) * Refactoring the Excel Text functions * More unit tests for utf-8 handling, for edge cases, and for argument validations --- .../Calculation/Calculation.php | 68 +-- src/PhpSpreadsheet/Calculation/TextData.php | 503 +++++------------- .../Calculation/TextData/CaseConvert.php | 64 +++ .../Calculation/TextData/CharacterConvert.php | 69 +++ .../Calculation/TextData/Concatenate.php | 82 +++ .../Calculation/TextData/Extract.php | 77 +++ .../Calculation/TextData/Format.php | 196 +++++++ .../Calculation/TextData/Replace.php | 65 +++ .../Calculation/TextData/Search.php | 80 +++ .../Calculation/TextData/Text.php | 59 ++ .../Calculation/TextData/Trim.php | 58 ++ .../Functions/TextData/LeftTest.php | 42 ++ .../Functions/TextData/LowerTest.php | 41 ++ .../Functions/TextData/MidTest.php | 43 ++ .../Functions/TextData/ProperTest.php | 41 ++ .../Functions/TextData/ReptTest.php | 20 +- .../Functions/TextData/RightTest.php | 42 ++ .../Functions/TextData/UpperTest.php | 41 ++ tests/data/Calculation/TextData/CLEAN.php | 4 + tests/data/Calculation/TextData/FIND.php | 30 ++ tests/data/Calculation/TextData/LEFT.php | 20 + tests/data/Calculation/TextData/LOWER.php | 12 + tests/data/Calculation/TextData/MID.php | 26 +- tests/data/Calculation/TextData/PROPER.php | 12 + tests/data/Calculation/TextData/REPLACE.php | 28 + tests/data/Calculation/TextData/REPT.php | 3 + tests/data/Calculation/TextData/RIGHT.php | 20 + tests/data/Calculation/TextData/SEARCH.php | 30 ++ .../data/Calculation/TextData/SUBSTITUTE.php | 34 ++ tests/data/Calculation/TextData/TEXTJOIN.php | 12 + tests/data/Calculation/TextData/UPPER.php | 12 + 31 files changed, 1424 insertions(+), 410 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Concatenate.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Extract.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Format.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Replace.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Search.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Text.php create mode 100644 src/PhpSpreadsheet/Calculation/TextData/Trim.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 9317699b..c5dbaa53 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -483,7 +483,7 @@ class Calculation ], 'CHAR' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'CHARACTER'], + 'functionCall' => [TextData\CharacterConvert::class, 'character'], 'argumentCount' => '1', ], 'CHIDIST' => [ @@ -533,12 +533,12 @@ class Calculation ], 'CLEAN' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'TRIMNONPRINTABLE'], + 'functionCall' => [TextData\Trim::class, 'nonPrintable'], 'argumentCount' => '1', ], 'CODE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'ASCIICODE'], + 'functionCall' => [TextData\CharacterConvert::class, 'code'], 'argumentCount' => '1', ], 'COLUMN' => [ @@ -570,12 +570,12 @@ class Calculation ], 'CONCAT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'CONCATENATE'], + 'functionCall' => [TextData\Concatenate::class, 'CONCATENATE'], 'argumentCount' => '1+', ], 'CONCATENATE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'CONCATENATE'], + 'functionCall' => [TextData\Concatenate::class, 'CONCATENATE'], 'argumentCount' => '1+', ], 'CONFIDENCE' => [ @@ -870,7 +870,7 @@ class Calculation ], 'DOLLAR' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'DOLLAR'], + 'functionCall' => [TextData\Format::class, 'DOLLAR'], 'argumentCount' => '1,2', ], 'DOLLARDE' => [ @@ -970,7 +970,7 @@ class Calculation ], 'EXACT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'EXACT'], + 'functionCall' => [TextData\Text::class, 'exact'], 'argumentCount' => '2', ], 'EXP' => [ @@ -1030,12 +1030,12 @@ class Calculation ], 'FIND' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'SEARCHSENSITIVE'], + 'functionCall' => [TextData\Search::class, 'sensitive'], 'argumentCount' => '2,3', ], 'FINDB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'SEARCHSENSITIVE'], + 'functionCall' => [TextData\Search::class, 'sensitive'], 'argumentCount' => '2,3', ], 'FINV' => [ @@ -1065,7 +1065,7 @@ class Calculation ], 'FIXED' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'FIXEDFORMAT'], + 'functionCall' => [TextData\Format::class, 'FIXEDFORMAT'], 'argumentCount' => '1-3', ], 'FLOOR' => [ @@ -1541,22 +1541,22 @@ class Calculation ], 'LEFT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'LEFT'], + 'functionCall' => [TextData\Extract::class, 'left'], 'argumentCount' => '1,2', ], 'LEFTB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'LEFT'], + 'functionCall' => [TextData\Extract::class, 'left'], 'argumentCount' => '1,2', ], 'LEN' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'STRINGLENGTH'], + 'functionCall' => [TextData\Text::class, 'length'], 'argumentCount' => '1', ], 'LENB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'STRINGLENGTH'], + 'functionCall' => [TextData\Text::class, 'length'], 'argumentCount' => '1', ], 'LINEST' => [ @@ -1611,7 +1611,7 @@ class Calculation ], 'LOWER' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'LOWERCASE'], + 'functionCall' => [TextData\CaseConvert::class, 'lower'], 'argumentCount' => '1', ], 'MATCH' => [ @@ -1656,12 +1656,12 @@ class Calculation ], 'MID' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'MID'], + 'functionCall' => [TextData\Extract::class, 'mid'], 'argumentCount' => '3', ], 'MIDB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'MID'], + 'functionCall' => [TextData\Extract::class, 'mid'], 'argumentCount' => '3', ], 'MIN' => [ @@ -1836,7 +1836,7 @@ class Calculation ], 'NUMBERVALUE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'NUMBERVALUE'], + 'functionCall' => [TextData\Format::class, 'NUMBERVALUE'], 'argumentCount' => '1+', ], 'OCT2BIN' => [ @@ -2008,7 +2008,7 @@ class Calculation ], 'PROPER' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'PROPERCASE'], + 'functionCall' => [TextData\CaseConvert::class, 'proper'], 'argumentCount' => '1', ], 'PV' => [ @@ -2083,27 +2083,27 @@ class Calculation ], 'REPLACE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'REPLACE'], + 'functionCall' => [TextData\Replace::class, 'replace'], 'argumentCount' => '4', ], 'REPLACEB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'REPLACE'], + 'functionCall' => [TextData\Replace::class, 'replace'], 'argumentCount' => '4', ], 'REPT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'builtinREPT'], + 'functionCall' => [TextData\Concatenate::class, 'builtinREPT'], 'argumentCount' => '2', ], 'RIGHT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'RIGHT'], + 'functionCall' => [TextData\Extract::class, 'right'], 'argumentCount' => '1,2', ], 'RIGHTB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'RIGHT'], + 'functionCall' => [TextData\Extract::class, 'right'], 'argumentCount' => '1,2', ], 'ROMAN' => [ @@ -2155,12 +2155,12 @@ class Calculation ], 'SEARCH' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'SEARCHINSENSITIVE'], + 'functionCall' => [TextData\Search::class, 'insensitive'], 'argumentCount' => '2,3', ], 'SEARCHB' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'SEARCHINSENSITIVE'], + 'functionCall' => [TextData\Search::class, 'insensitive'], 'argumentCount' => '2,3', ], 'SEC' => [ @@ -2300,7 +2300,7 @@ class Calculation ], 'SUBSTITUTE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'SUBSTITUTE'], + 'functionCall' => [TextData\Replace::class, 'substitute'], 'argumentCount' => '3,4', ], 'SUBTOTAL' => [ @@ -2361,7 +2361,7 @@ class Calculation ], 'T' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'RETURNSTRING'], + 'functionCall' => [TextData\Text::class, 'test'], 'argumentCount' => '1', ], 'TAN' => [ @@ -2411,7 +2411,7 @@ class Calculation ], 'TEXT' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'TEXTFORMAT'], + 'functionCall' => [TextData\Format::class, 'TEXTFORMAT'], 'argumentCount' => '2', ], 'TEXTJOIN' => [ @@ -2461,7 +2461,7 @@ class Calculation ], 'TRIM' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'TRIMSPACES'], + 'functionCall' => [TextData\Trim::class, 'spaces'], 'argumentCount' => '1', ], 'TRIMMEAN' => [ @@ -2496,12 +2496,12 @@ class Calculation ], 'UNICHAR' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'CHARACTER'], + 'functionCall' => [TextData\CharacterConvert::class, 'character'], 'argumentCount' => '1', ], 'UNICODE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'ASCIICODE'], + 'functionCall' => [TextData\CharacterConvert::class, 'code'], 'argumentCount' => '1', ], 'UNIQUE' => [ @@ -2511,7 +2511,7 @@ class Calculation ], 'UPPER' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'UPPERCASE'], + 'functionCall' => [TextData\CaseConvert::class, 'upper'], 'argumentCount' => '1', ], 'USDOLLAR' => [ @@ -2521,7 +2521,7 @@ class Calculation ], 'VALUE' => [ 'category' => Category::CATEGORY_TEXT_AND_DATA, - 'functionCall' => [TextData::class, 'VALUE'], + 'functionCall' => [TextData\Format::class, 'VALUE'], 'argumentCount' => '1', ], 'VAR' => [ diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index b886ce08..c7e91a47 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -3,141 +3,88 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use DateTimeInterface; -use PhpOffice\PhpSpreadsheet\Shared\Date; -use PhpOffice\PhpSpreadsheet\Shared\StringHelper; -use PhpOffice\PhpSpreadsheet\Style\NumberFormat; +/** + * @deprecated 1.18.0 + */ class TextData { - private static $invalidChars; - - private static function unicodeToOrd($character) - { - return unpack('V', iconv('UTF-8', 'UCS-4LE', $character))[1]; - } - /** * CHARACTER. * + * @Deprecated 1.18.0 + * + * @see Use the character() method in the TextData\CharacterConvert class instead + * * @param string $character Value * * @return string */ public static function CHARACTER($character) { - $character = Functions::flattenSingleValue($character); - - if (!is_numeric($character)) { - return Functions::VALUE(); - } - $character = (int) $character; - if ($character < 1 || $character > 255) { - return Functions::VALUE(); - } - - return iconv('UCS-4LE', 'UTF-8', pack('V', $character)); + return TextData\CharacterConvert::character($character); } /** * TRIMNONPRINTABLE. * + * @Deprecated 1.18.0 + * + * @see Use the nonPrintable() method in the TextData\Trim class instead + * * @param mixed $stringValue Value to check * * @return string */ public static function TRIMNONPRINTABLE($stringValue = '') { - $stringValue = Functions::flattenSingleValue($stringValue); - - if (is_bool($stringValue)) { - return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - if (self::$invalidChars === null) { - self::$invalidChars = range(chr(0), chr(31)); - } - - if (is_string($stringValue) || is_numeric($stringValue)) { - return str_replace(self::$invalidChars, '', trim($stringValue, "\x00..\x1F")); - } - - return null; + return TextData\Trim::nonPrintable($stringValue); } /** * TRIMSPACES. * + * @Deprecated 1.18.0 + * + * @see Use the spaces() method in the TextData\Trim class instead + * * @param mixed $stringValue Value to check * * @return string */ public static function TRIMSPACES($stringValue = '') { - $stringValue = Functions::flattenSingleValue($stringValue); - if (is_bool($stringValue)) { - return ($stringValue) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - if (is_string($stringValue) || is_numeric($stringValue)) { - return trim(preg_replace('/ +/', ' ', trim($stringValue, ' ')), ' '); - } - - return null; - } - - private static function convertBooleanValue($value) - { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { - return (int) $value; - } - - return ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); + return TextData\Trim::spaces($stringValue); } /** * ASCIICODE. * + * @Deprecated 1.18.0 + * + * @see Use the code() method in the TextData\CharacterConvert class instead + * * @param string $characters Value * * @return int|string A string if arguments are invalid */ public static function ASCIICODE($characters) { - if (($characters === null) || ($characters === '')) { - return Functions::VALUE(); - } - $characters = Functions::flattenSingleValue($characters); - if (is_bool($characters)) { - $characters = self::convertBooleanValue($characters); - } - - $character = $characters; - if (mb_strlen($characters, 'UTF-8') > 1) { - $character = mb_substr($characters, 0, 1, 'UTF-8'); - } - - return self::unicodeToOrd($character); + return TextData\CharacterConvert::code($characters); } /** * CONCATENATE. * + * @Deprecated 1.18.0 + * + * @see Use the CONCATENATE() method in the TextData\Concatenate class instead + * * @return string */ public static function CONCATENATE(...$args) { - $returnValue = ''; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - if (is_bool($arg)) { - $arg = self::convertBooleanValue($arg); - } - $returnValue .= $arg; - } - - return $returnValue; + return TextData\Concatenate::CONCATENATE(...$args); } /** @@ -146,6 +93,10 @@ class TextData * This function converts a number to text using currency format, with the decimals rounded to the specified place. * The format used is $#,##0.00_);($#,##0.00).. * + * @Deprecated 1.18.0 + * + * @see Use the DOLLAR() method in the TextData\Format class instead + * * @param float $value The value to format * @param int $decimals The number of digits to display to the right of the decimal point. * If decimals is negative, number is rounded to the left of the decimal point. @@ -155,33 +106,16 @@ class TextData */ public static function DOLLAR($value = 0, $decimals = 2) { - $value = Functions::flattenSingleValue($value); - $decimals = $decimals === null ? 0 : Functions::flattenSingleValue($decimals); - - // Validate parameters - if (!is_numeric($value) || !is_numeric($decimals)) { - return Functions::VALUE(); - } - $decimals = (int) $decimals; - - $mask = '$#,##0'; - if ($decimals > 0) { - $mask .= '.' . str_repeat('0', $decimals); - } else { - $round = 10 ** abs($decimals); - if ($value < 0) { - $round = 0 - $round; - } - $value = MathTrig\Mround::funcMround($value, $round); - } - $mask = "$mask;($mask)"; - - return NumberFormat::toFormattedString($value, $mask); + return TextData\Format::DOLLAR($value, $decimals); } /** * SEARCHSENSITIVE. * + * @Deprecated 1.18.0 + * + * @see Use the sensitive() method in the TextData\Search class instead + * * @param string $needle The string to look for * @param string $haystack The string in which to look * @param int $offset Offset within $haystack @@ -190,33 +124,16 @@ class TextData */ public static function SEARCHSENSITIVE($needle, $haystack, $offset = 1) { - $needle = Functions::flattenSingleValue($needle); - $haystack = Functions::flattenSingleValue($haystack); - $offset = Functions::flattenSingleValue($offset); - - if (!is_bool($needle)) { - if (is_bool($haystack)) { - $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) { - if (StringHelper::countCharacters($needle) === 0) { - return $offset; - } - - $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8'); - if ($pos !== false) { - return ++$pos; - } - } - } - - return Functions::VALUE(); + return TextData\Search::sensitive($needle, $haystack, $offset); } /** * SEARCHINSENSITIVE. * + * @Deprecated 1.18.0 + * + * @see Use the insensitive() method in the TextData\Search class instead + * * @param string $needle The string to look for * @param string $haystack The string in which to look * @param int $offset Offset within $haystack @@ -225,33 +142,16 @@ class TextData */ public static function SEARCHINSENSITIVE($needle, $haystack, $offset = 1) { - $needle = Functions::flattenSingleValue($needle); - $haystack = Functions::flattenSingleValue($haystack); - $offset = Functions::flattenSingleValue($offset); - - if (!is_bool($needle)) { - if (is_bool($haystack)) { - $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) { - if (StringHelper::countCharacters($needle) === 0) { - return $offset; - } - - $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8'); - if ($pos !== false) { - return ++$pos; - } - } - } - - return Functions::VALUE(); + return TextData\Search::insensitive($needle, $haystack, $offset); } /** * FIXEDFORMAT. * + * @Deprecated 1.18.0 + * + * @see Use the FIXEDFORMAT() method in the TextData\Format class instead + * * @param mixed $value Value to check * @param int $decimals * @param bool $no_commas @@ -260,35 +160,16 @@ class TextData */ public static function FIXEDFORMAT($value, $decimals = 2, $no_commas = false) { - $value = Functions::flattenSingleValue($value); - $decimals = Functions::flattenSingleValue($decimals); - $no_commas = Functions::flattenSingleValue($no_commas); - - // Validate parameters - if (!is_numeric($value) || !is_numeric($decimals)) { - return Functions::VALUE(); - } - $decimals = (int) floor($decimals); - - $valueResult = round($value, $decimals); - if ($decimals < 0) { - $decimals = 0; - } - if (!$no_commas) { - $valueResult = number_format( - $valueResult, - $decimals, - StringHelper::getDecimalSeparator(), - StringHelper::getThousandsSeparator() - ); - } - - return (string) $valueResult; + return TextData\Format::FIXEDFORMAT($value, $decimals, $no_commas); } /** * LEFT. * + * @Deprecated 1.18.0 + * + * @see Use the left() method in the TextData\Extract class instead + * * @param string $value Value * @param int $chars Number of characters * @@ -296,23 +177,16 @@ class TextData */ public static function LEFT($value = '', $chars = 1) { - $value = Functions::flattenSingleValue($value); - $chars = Functions::flattenSingleValue($chars); - - if (!is_numeric($chars) || $chars < 0) { - return Functions::VALUE(); - } - - if (is_bool($value)) { - $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return mb_substr($value, 0, $chars, 'UTF-8'); + return TextData\Extract::left($value, $chars); } /** * MID. * + * @Deprecated 1.18.0 + * + * @see Use the mid() method in the TextData\Extract class instead + * * @param string $value Value * @param int $start Start character * @param int $chars Number of characters @@ -321,24 +195,16 @@ class TextData */ public static function MID($value = '', $start = 1, $chars = null) { - $value = Functions::flattenSingleValue($value); - $start = Functions::flattenSingleValue($start); - $chars = Functions::flattenSingleValue($chars); - - if (!is_numeric($start) || $start < 1 || !is_numeric($chars) || $chars < 0) { - return Functions::VALUE(); - } - - if (is_bool($value)) { - $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return mb_substr($value, --$start, $chars, 'UTF-8'); + return TextData\Extract::mid($value, $start, $chars); } /** * RIGHT. * + * @Deprecated 1.18.0 + * + * @see Use the right() method in the TextData\Extract class instead + * * @param string $value Value * @param int $chars Number of characters * @@ -346,36 +212,23 @@ class TextData */ public static function RIGHT($value = '', $chars = 1) { - $value = Functions::flattenSingleValue($value); - $chars = Functions::flattenSingleValue($chars); - - if (!is_numeric($chars) || $chars < 0) { - return Functions::VALUE(); - } - - if (is_bool($value)) { - $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return mb_substr($value, mb_strlen($value, 'UTF-8') - $chars, $chars, 'UTF-8'); + return TextData\Extract::right($value, $chars); } /** * STRINGLENGTH. * + * @Deprecated 1.18.0 + * + * @see Use the length() method in the TextData\Text class instead + * * @param string $value Value * * @return int */ public static function STRINGLENGTH($value = '') { - $value = Functions::flattenSingleValue($value); - - if (is_bool($value)) { - $value = ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return mb_strlen($value, 'UTF-8'); + return TextData\Text::length($value); } /** @@ -383,19 +236,17 @@ class TextData * * Converts a string value to upper case. * + * @Deprecated 1.18.0 + * + * @see Use the lower() method in the TextData\CaseConvert class instead + * * @param string $mixedCaseString * * @return string */ public static function LOWERCASE($mixedCaseString) { - $mixedCaseString = Functions::flattenSingleValue($mixedCaseString); - - if (is_bool($mixedCaseString)) { - $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return StringHelper::strToLower($mixedCaseString); + return TextData\CaseConvert::lower($mixedCaseString); } /** @@ -403,19 +254,17 @@ class TextData * * Converts a string value to upper case. * + * @Deprecated 1.18.0 + * + * @see Use the upper() method in the TextData\CaseConvert class instead + * * @param string $mixedCaseString * * @return string */ public static function UPPERCASE($mixedCaseString) { - $mixedCaseString = Functions::flattenSingleValue($mixedCaseString); - - if (is_bool($mixedCaseString)) { - $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return StringHelper::strToUpper($mixedCaseString); + return TextData\CaseConvert::upper($mixedCaseString); } /** @@ -423,24 +272,26 @@ class TextData * * Converts a string value to upper case. * + * @Deprecated 1.18.0 + * + * @see Use the proper() method in the TextData\CaseConvert class instead + * * @param string $mixedCaseString * * @return string */ public static function PROPERCASE($mixedCaseString) { - $mixedCaseString = Functions::flattenSingleValue($mixedCaseString); - - if (is_bool($mixedCaseString)) { - $mixedCaseString = ($mixedCaseString) ? Calculation::getTRUE() : Calculation::getFALSE(); - } - - return StringHelper::strToTitle($mixedCaseString); + return TextData\CaseConvert::proper($mixedCaseString); } /** * REPLACE. * + * @Deprecated 1.18.0 + * + * @see Use the replace() method in the TextData\Replace class instead + * * @param string $oldText String to modify * @param int $start Start character * @param int $chars Number of characters @@ -450,20 +301,16 @@ class TextData */ public static function REPLACE($oldText, $start, $chars, $newText) { - $oldText = Functions::flattenSingleValue($oldText); - $start = Functions::flattenSingleValue($start); - $chars = Functions::flattenSingleValue($chars); - $newText = Functions::flattenSingleValue($newText); - - $left = self::LEFT($oldText, $start - 1); - $right = self::RIGHT($oldText, self::STRINGLENGTH($oldText) - ($start + $chars) + 1); - - return $left . $newText . $right; + return TextData\Replace::replace($oldText, $start, $chars, $newText); } /** * SUBSTITUTE. * + * @Deprecated 1.18.0 + * + * @see Use the substitute() method in the TextData\Replace class instead + * * @param string $text Value * @param string $fromText From Value * @param string $toText To Value @@ -473,52 +320,32 @@ class TextData */ public static function SUBSTITUTE($text = '', $fromText = '', $toText = '', $instance = 0) { - $text = Functions::flattenSingleValue($text); - $fromText = Functions::flattenSingleValue($fromText); - $toText = Functions::flattenSingleValue($toText); - $instance = floor(Functions::flattenSingleValue($instance)); - - if ($instance == 0) { - return str_replace($fromText, $toText, $text); - } - - $pos = -1; - while ($instance > 0) { - $pos = mb_strpos($text, $fromText, $pos + 1, 'UTF-8'); - if ($pos === false) { - break; - } - --$instance; - } - - if ($pos !== false) { - return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText); - } - - return $text; + return TextData\Replace::substitute($text, $fromText, $toText, $instance); } /** * RETURNSTRING. * + * @Deprecated 1.18.0 + * + * @see Use the test() method in the TextData\Text class instead + * * @param mixed $testValue Value to check * * @return null|string */ public static function RETURNSTRING($testValue = '') { - $testValue = Functions::flattenSingleValue($testValue); - - if (is_string($testValue)) { - return $testValue; - } - - return null; + return TextData\Text::test($testValue); } /** * TEXTFORMAT. * + * @Deprecated 1.18.0 + * + * @see Use the TEXTFORMAT() method in the TextData\Format class instead + * * @param mixed $value Value to check * @param string $format Format mask to use * @@ -526,65 +353,32 @@ class TextData */ public static function TEXTFORMAT($value, $format) { - $value = Functions::flattenSingleValue($value); - $format = Functions::flattenSingleValue($format); - - if ((is_string($value)) && (!is_numeric($value)) && Date::isDateTimeFormatCode($format)) { - $value = DateTime::DATEVALUE($value); - } - - return (string) NumberFormat::toFormattedString($value, $format); + return TextData\Format::TEXTFORMAT($value, $format); } /** * VALUE. * + * @Deprecated 1.18.0 + * + * @see Use the VALUE() method in the TextData\Format class instead + * * @param mixed $value Value to check * * @return DateTimeInterface|float|int|string A string if arguments are invalid */ public static function VALUE($value = '') { - $value = Functions::flattenSingleValue($value); - - if (!is_numeric($value)) { - $numberValue = str_replace( - StringHelper::getThousandsSeparator(), - '', - trim($value, " \t\n\r\0\x0B" . StringHelper::getCurrencyCode()) - ); - if (is_numeric($numberValue)) { - return (float) $numberValue; - } - - $dateSetting = Functions::getReturnDateType(); - Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); - - if (strpos($value, ':') !== false) { - $timeValue = DateTime::TIMEVALUE($value); - if ($timeValue !== Functions::VALUE()) { - Functions::setReturnDateType($dateSetting); - - return $timeValue; - } - } - $dateValue = DateTime::DATEVALUE($value); - if ($dateValue !== Functions::VALUE()) { - Functions::setReturnDateType($dateSetting); - - return $dateValue; - } - Functions::setReturnDateType($dateSetting); - - return Functions::VALUE(); - } - - return (float) $value; + return TextData\Format::VALUE($value); } /** * NUMBERVALUE. * + * @Deprecated 1.18.0 + * + * @see Use the NUMBERVALUE() method in the TextData\Format class instead + * * @param mixed $value Value to check * @param string $decimalSeparator decimal separator, defaults to locale defined value * @param string $groupSeparator group/thosands separator, defaults to locale defined value @@ -593,39 +387,7 @@ class TextData */ public static function NUMBERVALUE($value = '', $decimalSeparator = null, $groupSeparator = null) { - $value = Functions::flattenSingleValue($value); - $decimalSeparator = Functions::flattenSingleValue($decimalSeparator); - $groupSeparator = Functions::flattenSingleValue($groupSeparator); - - if (!is_numeric($value)) { - $decimalSeparator = empty($decimalSeparator) ? StringHelper::getDecimalSeparator() : $decimalSeparator; - $groupSeparator = empty($groupSeparator) ? StringHelper::getThousandsSeparator() : $groupSeparator; - - $decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator) . '/', $value, $matches, PREG_OFFSET_CAPTURE); - if ($decimalPositions > 1) { - return Functions::VALUE(); - } - $decimalOffset = array_pop($matches[0])[1]; - if (strpos($value, $groupSeparator, $decimalOffset) !== false) { - return Functions::VALUE(); - } - - $value = str_replace([$groupSeparator, $decimalSeparator], ['', '.'], $value); - - // Handle the special case of trailing % signs - $percentageString = rtrim($value, '%'); - if (!is_numeric($percentageString)) { - return Functions::VALUE(); - } - - $percentageAdjustment = strlen($value) - strlen($percentageString); - if ($percentageAdjustment) { - $value = (float) $percentageString; - $value /= 10 ** ($percentageAdjustment * 2); - } - } - - return (float) $value; + return TextData\Format::NUMBERVALUE($value, $decimalSeparator, $groupSeparator); } /** @@ -633,6 +395,10 @@ class TextData * EXACT is case-sensitive but ignores formatting differences. * Use EXACT to test text being entered into a document. * + * @Deprecated 1.18.0 + * + * @see Use the exact() method in the TextData\Text class instead + * * @param $value1 * @param $value2 * @@ -640,15 +406,16 @@ class TextData */ public static function EXACT($value1, $value2) { - $value1 = Functions::flattenSingleValue($value1); - $value2 = Functions::flattenSingleValue($value2); - - return (string) $value2 === (string) $value1; + return TextData\Text::exact($value1, $value2); } /** * TEXTJOIN. * + * @Deprecated 1.18.0 + * + * @see Use the TEXTJOIN() method in the TextData\Concatenate class instead + * * @param mixed $delimiter * @param mixed $ignoreEmpty * @param mixed $args @@ -657,23 +424,17 @@ class TextData */ public static function TEXTJOIN($delimiter, $ignoreEmpty, ...$args) { - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $key => &$arg) { - if ($ignoreEmpty && trim($arg) == '') { - unset($aArgs[$key]); - } elseif (is_bool($arg)) { - $arg = self::convertBooleanValue($arg); - } - } - - return implode($delimiter, $aArgs); + return TextData\Concatenate::TEXTJOIN($delimiter, $ignoreEmpty, ...$args); } /** * REPT. * - * Returns the result of builtin function round after validating args. + * Returns the result of builtin function repeat after validating args. + * + * @Deprecated 1.18.0 + * + * @see Use the builtinREPT() method in the TextData\Concatenate class instead * * @param string $str Should be numeric * @param mixed $number Should be int @@ -682,12 +443,6 @@ class TextData */ public static function builtinREPT($str, $number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number) || $number < 0) { - return Functions::VALUE(); - } - - return str_repeat($str, $number); + return TextData\Concatenate::builtinREPT($str, $number); } } diff --git a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php new file mode 100644 index 00000000..2a275133 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php @@ -0,0 +1,64 @@ + 255) { + return Functions::VALUE(); + } + + return iconv('UCS-4LE', 'UTF-8', pack('V', $character)); + } + + /** + * ASCIICODE. + * + * @param string $characters Value + * + * @return int|string A string if arguments are invalid + */ + public static function code($characters) + { + if (($characters === null) || ($characters === '')) { + return Functions::VALUE(); + } + $characters = Functions::flattenSingleValue($characters); + if (is_bool($characters)) { + $characters = self::convertBooleanValue($characters); + } + + $character = $characters; + if (mb_strlen($characters, 'UTF-8') > 1) { + $character = mb_substr($characters, 0, 1, 'UTF-8'); + } + + return self::unicodeToOrd($character); + } + + private static function unicodeToOrd($character) + { + return unpack('V', iconv('UTF-8', 'UCS-4LE', $character))[1]; + } + + private static function convertBooleanValue($value) + { + if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) { + return (int) $value; + } + + return ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/TextData/Concatenate.php b/src/PhpSpreadsheet/Calculation/TextData/Concatenate.php new file mode 100644 index 00000000..5780bb6e --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/TextData/Concatenate.php @@ -0,0 +1,82 @@ + &$arg) { + if ($ignoreEmpty === true && is_string($arg) && trim($arg) === '') { + unset($aArgs[$key]); + } elseif (is_bool($arg)) { + $arg = self::convertBooleanValue($arg); + } + } + + return implode($delimiter, $aArgs); + } + + /** + * REPT. + * + * Returns the result of builtin function round after validating args. + * + * @param mixed $stringValue The value to repeat + * @param mixed $repeatCount The number of times the string value should be repeated + */ + public static function builtinREPT($stringValue, $repeatCount): string + { + $repeatCount = Functions::flattenSingleValue($repeatCount); + + if (!is_numeric($repeatCount) || $repeatCount < 0) { + return Functions::VALUE(); + } + + if (is_bool($stringValue)) { + $stringValue = self::convertBooleanValue($stringValue); + } + + return str_repeat($stringValue, (int) $repeatCount); + } + + private static function convertBooleanValue($value) + { + if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { + return (int) $value; + } + + return ($value) ? Calculation::getTRUE() : Calculation::getFALSE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/TextData/Extract.php b/src/PhpSpreadsheet/Calculation/TextData/Extract.php new file mode 100644 index 00000000..126d9f49 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/TextData/Extract.php @@ -0,0 +1,77 @@ + 0) { + $mask .= '.' . str_repeat('0', $decimals); + } else { + $round = 10 ** abs($decimals); + if ($value < 0) { + $round = 0 - $round; + } + $value = MathTrig\Mround::funcMround($value, $round); + } + $mask = "$mask;($mask)"; + + return NumberFormat::toFormattedString($value, $mask); + } + + /** + * FIXEDFORMAT. + * + * @param mixed $value Value to check + * @param mixed $decimals + * @param bool $noCommas + */ + public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false): string + { + $value = Functions::flattenSingleValue($value); + $decimals = $decimals === null ? 2 : Functions::flattenSingleValue($decimals); + $noCommas = Functions::flattenSingleValue($noCommas); + + // Validate parameters + if (!is_numeric($value) || !is_numeric($decimals)) { + return Functions::VALUE(); + } + $decimals = (int) floor($decimals); + + $valueResult = round($value, $decimals); + if ($decimals < 0) { + $decimals = 0; + } + if (!$noCommas) { + $valueResult = number_format( + $valueResult, + $decimals, + StringHelper::getDecimalSeparator(), + StringHelper::getThousandsSeparator() + ); + } + + return (string) $valueResult; + } + + /** + * TEXTFORMAT. + * + * @param mixed $value Value to check + * @param string $format Format mask to use + */ + public static function TEXTFORMAT($value, $format): string + { + $value = Functions::flattenSingleValue($value); + $format = Functions::flattenSingleValue($format); + + if ((is_string($value)) && (!is_numeric($value)) && Date::isDateTimeFormatCode($format)) { + $value = DateTime::DATEVALUE($value); + } + + return (string) NumberFormat::toFormattedString($value, $format); + } + + /** + * VALUE. + * + * @param mixed $value Value to check + * + * @return DateTimeInterface|float|int|string A string if arguments are invalid + */ + public static function VALUE($value = '') + { + $value = Functions::flattenSingleValue($value); + + if (!is_numeric($value)) { + $numberValue = str_replace( + StringHelper::getThousandsSeparator(), + '', + trim($value, " \t\n\r\0\x0B" . StringHelper::getCurrencyCode()) + ); + if (is_numeric($numberValue)) { + return (float) $numberValue; + } + + $dateSetting = Functions::getReturnDateType(); + Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); + + if (strpos($value, ':') !== false) { + $timeValue = DateTime::TIMEVALUE($value); + if ($timeValue !== Functions::VALUE()) { + Functions::setReturnDateType($dateSetting); + + return $timeValue; + } + } + $dateValue = DateTime::DATEVALUE($value); + if ($dateValue !== Functions::VALUE()) { + Functions::setReturnDateType($dateSetting); + + return $dateValue; + } + Functions::setReturnDateType($dateSetting); + + return Functions::VALUE(); + } + + return (float) $value; + } + + /** + * NUMBERVALUE. + * + * @param mixed $value Value to check + * @param string $decimalSeparator decimal separator, defaults to locale defined value + * @param string $groupSeparator group/thosands separator, defaults to locale defined value + * + * @return float|string + */ + public static function NUMBERVALUE($value = '', $decimalSeparator = null, $groupSeparator = null) + { + $value = Functions::flattenSingleValue($value); + $decimalSeparator = Functions::flattenSingleValue($decimalSeparator); + $groupSeparator = Functions::flattenSingleValue($groupSeparator); + + if (!is_numeric($value)) { + $decimalSeparator = empty($decimalSeparator) ? StringHelper::getDecimalSeparator() : $decimalSeparator; + $groupSeparator = empty($groupSeparator) ? StringHelper::getThousandsSeparator() : $groupSeparator; + + $decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator) . '/', $value, $matches, PREG_OFFSET_CAPTURE); + if ($decimalPositions > 1) { + return Functions::VALUE(); + } + $decimalOffset = array_pop($matches[0])[1]; + if (strpos($value, $groupSeparator, $decimalOffset) !== false) { + return Functions::VALUE(); + } + + $value = str_replace([$groupSeparator, $decimalSeparator], ['', '.'], $value); + + // Handle the special case of trailing % signs + $percentageString = rtrim($value, '%'); + if (!is_numeric($percentageString)) { + return Functions::VALUE(); + } + + $percentageAdjustment = strlen($value) - strlen($percentageString); + if ($percentageAdjustment) { + $value = (float) $percentageString; + $value /= 10 ** ($percentageAdjustment * 2); + } + } + + return (float) $value; + } +} diff --git a/src/PhpSpreadsheet/Calculation/TextData/Replace.php b/src/PhpSpreadsheet/Calculation/TextData/Replace.php new file mode 100644 index 00000000..9a849ba0 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/TextData/Replace.php @@ -0,0 +1,65 @@ + 0) { + $pos = mb_strpos($text, $fromText, $pos + 1, 'UTF-8'); + if ($pos === false) { + break; + } + --$instance; + } + + if ($pos !== false) { + return self::REPLACE($text, ++$pos, mb_strlen($fromText, 'UTF-8'), $toText); + } + + return $text; + } +} diff --git a/src/PhpSpreadsheet/Calculation/TextData/Search.php b/src/PhpSpreadsheet/Calculation/TextData/Search.php new file mode 100644 index 00000000..acbe6a24 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/TextData/Search.php @@ -0,0 +1,80 @@ + 0) && (StringHelper::countCharacters($haystack) > $offset)) { + if (StringHelper::countCharacters($needle) === 0) { + return $offset; + } + + $pos = mb_strpos($haystack, $needle, --$offset, 'UTF-8'); + if ($pos !== false) { + return ++$pos; + } + } + } + + return Functions::VALUE(); + } + + /** + * SEARCHINSENSITIVE. + * + * @param string $needle The string to look for + * @param string $haystack The string in which to look + * @param int $offset Offset within $haystack + * + * @return int|string + */ + public static function insensitive($needle, $haystack, $offset = 1) + { + $needle = Functions::flattenSingleValue($needle); + $haystack = Functions::flattenSingleValue($haystack); + $offset = Functions::flattenSingleValue($offset); + + if (!is_bool($needle)) { + if (is_bool($haystack)) { + $haystack = ($haystack) ? Calculation::getTRUE() : Calculation::getFALSE(); + } + + if (($offset > 0) && (StringHelper::countCharacters($haystack) > $offset)) { + if (StringHelper::countCharacters($needle) === 0) { + return $offset; + } + + $pos = mb_stripos($haystack, $needle, --$offset, 'UTF-8'); + if ($pos !== false) { + return ++$pos; + } + } + } + + return Functions::VALUE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/TextData/Text.php b/src/PhpSpreadsheet/Calculation/TextData/Text.php new file mode 100644 index 00000000..a47d373b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/TextData/Text.php @@ -0,0 +1,59 @@ +expectException(CalcExp::class); @@ -24,6 +39,9 @@ class ReptTest extends TestCase $this->expectException(CalcExp::class); $formula = "=REPT($val)"; } else { + if (is_bool($val)) { + $val = ($val) ? Calculation::getTRUE() : Calculation::getFALSE(); + } $formula = "=REPT($val, $rpt)"; } $spreadsheet = new Spreadsheet(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php index 50fc86dc..da4c7491 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php @@ -3,10 +3,16 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\TextData; use PhpOffice\PhpSpreadsheet\Calculation\TextData; +use PhpOffice\PhpSpreadsheet\Settings; use PHPUnit\Framework\TestCase; class RightTest extends TestCase { + protected function tearDown(): void + { + Settings::setLocale('en_US'); + } + /** * @dataProvider providerRIGHT * @@ -22,4 +28,40 @@ class RightTest extends TestCase { return require 'tests/data/Calculation/TextData/RIGHT.php'; } + + /** + * @dataProvider providerLocaleRIGHT + * + * @param string $expectedResult + * @param $value + * @param mixed $locale + * @param mixed $characters + */ + public function testLowerWithLocaleBoolean($expectedResult, $locale, $value, $characters): void + { + $newLocale = Settings::setLocale($locale); + if ($newLocale === false) { + Settings::setLocale('en_US'); + self::markTestSkipped('Unable to set locale for locale-specific test'); + } + + $result = TextData::RIGHT($value, $characters); + self::assertEquals($expectedResult, $result); + + Settings::setLocale('en_US'); + } + + public function providerLocaleRIGHT() + { + return [ + ['RAI', 'fr_FR', true, 3], + ['AAR', 'nl_NL', true, 3], + ['OSI', 'fi', true, 3], + ['ИНА', 'bg', true, 3], + ['UX', 'fr_FR', false, 2], + ['WAAR', 'nl_NL', false, 4], + ['ÄTOSI', 'fi', false, 5], + ['ЖЬ', 'bg', false, 2], + ]; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php index 13fb0b86..cf2d569d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php @@ -3,10 +3,16 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\TextData; use PhpOffice\PhpSpreadsheet\Calculation\TextData; +use PhpOffice\PhpSpreadsheet\Settings; use PHPUnit\Framework\TestCase; class UpperTest extends TestCase { + protected function tearDown(): void + { + Settings::setLocale('en_US'); + } + /** * @dataProvider providerUPPER * @@ -23,4 +29,39 @@ class UpperTest extends TestCase { return require 'tests/data/Calculation/TextData/UPPER.php'; } + + /** + * @dataProvider providerLocaleLOWER + * + * @param string $expectedResult + * @param $value + * @param mixed $locale + */ + public function testLowerWithLocaleBoolean($expectedResult, $locale, $value): void + { + $newLocale = Settings::setLocale($locale); + if ($newLocale === false) { + Settings::setLocale('en_US'); + self::markTestSkipped('Unable to set locale for locale-specific test'); + } + + $result = TextData::UPPERCASE($value); + self::assertEquals($expectedResult, $result); + + Settings::setLocale('en_US'); + } + + public function providerLocaleLOWER() + { + return [ + ['VRAI', 'fr_FR', true], + ['WAAR', 'nl_NL', true], + ['TOSI', 'fi', true], + ['ИСТИНА', 'bg', true], + ['FAUX', 'fr_FR', false], + ['ONWAAR', 'nl_NL', false], + ['EPÄTOSI', 'fi', false], + ['ЛОЖЬ', 'bg', false], + ]; + } } diff --git a/tests/data/Calculation/TextData/CLEAN.php b/tests/data/Calculation/TextData/CLEAN.php index aab0fe3a..67608883 100644 --- a/tests/data/Calculation/TextData/CLEAN.php +++ b/tests/data/Calculation/TextData/CLEAN.php @@ -5,6 +5,10 @@ return [ 'HELLO ', 'HELLO ', ], + [ + ' HELLO ', + ' HELLO ', + ], [ 'HELLO', ' HELLO', diff --git a/tests/data/Calculation/TextData/FIND.php b/tests/data/Calculation/TextData/FIND.php index 7420841a..0a583456 100644 --- a/tests/data/Calculation/TextData/FIND.php +++ b/tests/data/Calculation/TextData/FIND.php @@ -31,6 +31,36 @@ return [ 'A', 'MARK BAKER', ], + [ + 1, + 'Ενα', + 'Ενα δύο τρία τέσσερα πέντε', + ], + [ + 9, + 'τρία', + 'Ενα δύο τρία τέσσερα πέντε', + ], + [ + 22, + 'πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + ], + [ + 1, + 'ΕΝΑ', + 'ΕΝΑ ΔΎΟ ΤΡΊΑ ΤΈΣΣΕΡΑ ΠΈΝΤΕ', + ], + [ + 9, + 'ΤΡΊΑ', + 'ΕΝΑ ΔΎΟ ΤΡΊΑ ΤΈΣΣΕΡΑ ΠΈΝΤΕ', + ], + [ + 22, + 'ΠΈΝΤΕ', + 'ΕΝΑ ΔΎΟ ΤΡΊΑ ΤΈΣΣΕΡΑ ΠΈΝΤΕ', + ], [ 2, 'a', diff --git a/tests/data/Calculation/TextData/LEFT.php b/tests/data/Calculation/TextData/LEFT.php index 96702f6b..d524dc36 100644 --- a/tests/data/Calculation/TextData/LEFT.php +++ b/tests/data/Calculation/TextData/LEFT.php @@ -11,6 +11,11 @@ return [ '', 1, ], + [ + '', + 'ABC', + 0, + ], [ '#VALUE!', 'QWERTYUIOP', @@ -31,6 +36,21 @@ return [ 'ABCDEFGHI', 3, ], + [ + 'Ενα', + 'Ενα δύο τρία τέσσερα πέντε', + 3, + ], + [ + 'Ενα δύο', + 'Ενα δύο τρία τέσσερα πέντε', + 7, + ], + [ + 'Ενα δύο τρία', + 'Ενα δύο τρία τέσσερα πέντε', + 12, + ], [ 'TR', true, diff --git a/tests/data/Calculation/TextData/LOWER.php b/tests/data/Calculation/TextData/LOWER.php index 2a4064bf..c5360b95 100644 --- a/tests/data/Calculation/TextData/LOWER.php +++ b/tests/data/Calculation/TextData/LOWER.php @@ -9,6 +9,18 @@ return [ 'mark baker', 'MARK BAKER', ], + [ + 'buenos días', + 'BUENOS DÍAS', + ], + [ + 'καλημερα', + 'ΚΑΛΗΜΕΡΑ', + ], + [ + 'доброе утро', + 'ДОБРОЕ УТРО', + ], [ 'true', true, diff --git a/tests/data/Calculation/TextData/MID.php b/tests/data/Calculation/TextData/MID.php index 71d90e8b..b434f670 100644 --- a/tests/data/Calculation/TextData/MID.php +++ b/tests/data/Calculation/TextData/MID.php @@ -16,7 +16,7 @@ return [ [ '#VALUE!', 'QWERTYUIOP', - -1, + 0, 1, ], [ @@ -48,12 +48,36 @@ return [ 8, 20, ], + [ + '', + 'QWERTYUIOP', + 999, + 2, + ], [ 'DEF', 'ABCDEFGHI', 4, 3, ], + [ + 'δύο', + 'Ενα δύο τρία τέσσερα πέντε', + 5, + 3, + ], + [ + 'δύο τρία', + 'Ενα δύο τρία τέσσερα πέντε', + 5, + 8, + ], + [ + 'τρία τέσσερα', + 'Ενα δύο τρία τέσσερα πέντε', + 9, + 12, + ], [ 'R', true, diff --git a/tests/data/Calculation/TextData/PROPER.php b/tests/data/Calculation/TextData/PROPER.php index 84c29096..8bbf0e5c 100644 --- a/tests/data/Calculation/TextData/PROPER.php +++ b/tests/data/Calculation/TextData/PROPER.php @@ -5,6 +5,18 @@ return [ 'Mark Baker', 'MARK BAKER', ], + [ + 'Buenos Días', + 'BUENOS DÍAS', + ], + [ + 'Καλημερα', + 'ΚΑΛΗΜΕΡΑ', + ], + [ + 'Доброе Утро', + 'ДОБРОЕ УТРО', + ], [ 'True', true, diff --git a/tests/data/Calculation/TextData/REPLACE.php b/tests/data/Calculation/TextData/REPLACE.php index 086d1290..09e22968 100644 --- a/tests/data/Calculation/TextData/REPLACE.php +++ b/tests/data/Calculation/TextData/REPLACE.php @@ -29,4 +29,32 @@ return [ 0, 'DFG', ], + [ + 'Ενα δύοτρίατέσσεραπέντε', + 'Εναδύοτρίατέσσεραπέντε', + 4, + 0, + ' ', + ], + [ + 'Ενα δύο τρίατέσσεραπέντε', + 'Ενα δύοτρίατέσσεραπέντε', + 8, + 0, + ' ', + ], + [ + 'Ενα δύο τρία τέσσεραπέντε', + 'Ενα δύο τρίατέσσεραπέντε', + 13, + 0, + ' ', + ], + [ + 'Ενα δύο τρία τέσσερα πέντε', + 'Ενα δύο τρία τέσσεραπέντε', + 21, + 0, + ' ', + ], ]; diff --git a/tests/data/Calculation/TextData/REPT.php b/tests/data/Calculation/TextData/REPT.php index 24dd87e8..2c8d1c0d 100644 --- a/tests/data/Calculation/TextData/REPT.php +++ b/tests/data/Calculation/TextData/REPT.php @@ -7,5 +7,8 @@ return [ ['ABCABCABC', '"ABC"', 3], ['ABCABC', '"ABC"', 2.2], ['', '"ABC"', 0], + ['TRUETRUE', true, 2], + ['111', 1, 3], + ['δύο δύο ', '"δύο "', 2], ['#VALUE!', '"ABC"', -1], ]; diff --git a/tests/data/Calculation/TextData/RIGHT.php b/tests/data/Calculation/TextData/RIGHT.php index 95dfe96e..e6928df2 100644 --- a/tests/data/Calculation/TextData/RIGHT.php +++ b/tests/data/Calculation/TextData/RIGHT.php @@ -31,6 +31,26 @@ return [ 'ABCDEFGHI', 3, ], + [ + '', + 'ABCDEFGHI', + 0, + ], + [ + 'πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + 5, + ], + [ + 'τέσσερα πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + 13, + ], + [ + 'τρία τέσσερα πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + 18, + ], [ 'UE', true, diff --git a/tests/data/Calculation/TextData/SEARCH.php b/tests/data/Calculation/TextData/SEARCH.php index 28cd98f8..579830f6 100644 --- a/tests/data/Calculation/TextData/SEARCH.php +++ b/tests/data/Calculation/TextData/SEARCH.php @@ -59,6 +59,36 @@ return [ '', 'Mark Baker', ], + [ + 1, + 'Ενα', + 'Ενα δύο τρία τέσσερα πέντε', + ], + [ + 9, + 'τρία', + 'Ενα δύο τρία τέσσερα πέντε', + ], + [ + 22, + 'πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + ], + [ + 1, + 'Ενα', + 'ΕΝΑ ΔΥΟ ΤΡΙΑ ΤΕΣΣΕΡΑ ΠΕΝΤΕ', + ], + [ + 9, + 'τρία', + 'ΕΝΑ ΔΎΟ ΤΡΊΑ ΤΈΣΣΕΡΑ ΠΈΝΤΕ', + ], + [ + 22, + 'πέντε', + 'ΕΝΑ ΔΎΟ ΤΡΊΑ ΤΈΣΣΕΡΑ ΠΈΝΤΕ', + ], [ '#VALUE!', 'BITE', diff --git a/tests/data/Calculation/TextData/SUBSTITUTE.php b/tests/data/Calculation/TextData/SUBSTITUTE.php index 23f66a18..97cb8d0f 100644 --- a/tests/data/Calculation/TextData/SUBSTITUTE.php +++ b/tests/data/Calculation/TextData/SUBSTITUTE.php @@ -20,6 +20,20 @@ return [ 'x', 1, ], + [ + 'Mark Bxker', + 'Mark Baker', + 'a', + 'x', + 2, + ], + [ + 'Mark Bakker', + 'Mark Baker', + 'k', + 'kk', + 2, + ], [ 'Mark Baker', 'Mark Baker', @@ -27,6 +41,26 @@ return [ 'a', 1, ], + [ + 'Ενα δύο αρία αέσσερα πέναε', + 'Ενα δύο τρία τέσσερα πέντε', + 'τ', + 'α', + ], + [ + 'Ενα δύο τρία αέσσερα πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + 'τ', + 'α', + 2, + ], + [ + 'Ενα δύο τρία ατέσσερα πέντε', + 'Ενα δύο τρία τέσσερα πέντε', + 'τ', + 'ατ', + 2, + ], 'Unicode equivalence is not supported' => [ "\u{0061}\u{030A}", "\u{0061}\u{030A}", diff --git a/tests/data/Calculation/TextData/TEXTJOIN.php b/tests/data/Calculation/TextData/TEXTJOIN.php index 9ad85e94..9c6b4246 100644 --- a/tests/data/Calculation/TextData/TEXTJOIN.php +++ b/tests/data/Calculation/TextData/TEXTJOIN.php @@ -5,10 +5,22 @@ return [ 'ABCDE,FGHIJ', [',', true, 'ABCDE', 'FGHIJ'], ], + [ + 'ABCDEFGHIJ', + ['', true, 'ABCDE', 'FGHIJ'], + ], [ '1-2-3', ['-', true, 1, 2, 3], ], + [ + '<<::>>', + ['::', true, '<<', '>>'], + ], + [ + 'Καλό απόγευμα', + [' ', true, 'Καλό', 'απόγευμα'], + ], [ 'Boolean-TRUE', ['-', true, 'Boolean', '', true], diff --git a/tests/data/Calculation/TextData/UPPER.php b/tests/data/Calculation/TextData/UPPER.php index b43163be..e5d2f18e 100644 --- a/tests/data/Calculation/TextData/UPPER.php +++ b/tests/data/Calculation/TextData/UPPER.php @@ -9,6 +9,18 @@ return [ 'MARK BAKER', 'mark baker', ], + [ + 'BUENOS DÍAS', + 'buenos días', + ], + [ + 'ΚΑΛΗΜΕΡΑ', + 'Καλημερα', + ], + [ + 'ДОБРОЕ УТРО', + 'доброе утро', + ], [ 'TRUE', true, From 07ad80075548344208a8a26d8d41d8b0a1789a61 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 24 Mar 2021 13:29:54 +0100 Subject: [PATCH 131/187] New Bessel Algorithm, providing a higher degree of accuracy and precision (#1946) * New Bessel Algorithm, providing a higher degree of precision (12 decimal places) and still matching/exceeding MS Excel's precision across the range of values --- .../Calculation/Engineering/BesselI.php | 106 +++- .../Calculation/Engineering/BesselJ.php | 141 ++++- .../Calculation/Engineering/BesselK.php | 60 ++- .../Calculation/Engineering/BesselY.php | 87 ++-- .../Functions/Engineering/BesselITest.php | 2 +- .../Functions/Engineering/BesselKTest.php | 2 +- .../Functions/Engineering/BesselYTest.php | 2 +- .../Functions/TextData/ReptTest.php | 6 +- .../data/Calculation/Engineering/BESSELI.php | 488 ++++++++++-------- .../data/Calculation/Engineering/BESSELJ.php | 360 +++++++++---- .../data/Calculation/Engineering/BESSELK.php | 252 +++++---- .../data/Calculation/Engineering/BESSELY.php | 213 +++++--- 12 files changed, 1078 insertions(+), 641 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php index eda5c12b..d39ac05c 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php @@ -3,7 +3,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class BesselI { @@ -16,9 +15,12 @@ class BesselI * Excel Function: * BESSELI(x,ord) * - * @param float $x The value at which to evaluate the function. + * NOTE: The MS Excel implementation of the BESSELI function is still not accurate. + * This code provides a more accurate calculation + * + * @param mixed (float) $x The value at which to evaluate the function. * If x is nonnumeric, BESSELI returns the #VALUE! error value. - * @param int $ord The order of the Bessel function. + * @param mixed (int) $ord The order of the Bessel function. * If ord is not an integer, it is truncated. * If $ord is nonnumeric, BESSELI returns the #VALUE! error value. * If $ord < 0, BESSELI returns the #NUM! error value. @@ -28,7 +30,7 @@ class BesselI public static function BESSELI($x, $ord) { $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); + $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); if ((is_numeric($x)) && (is_numeric($ord))) { $ord = (int) floor($ord); @@ -36,7 +38,7 @@ class BesselI return Functions::NAN(); } - $fResult = self::calculate($x, $ord); + $fResult = self::calculate((float) $x, $ord); return (is_nan($fResult)) ? Functions::NAN() : $fResult; } @@ -46,27 +48,87 @@ class BesselI private static function calculate(float $x, int $ord): float { - if (abs($x) <= 30) { - $fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord); - $ordK = 1; - $fSqrX = ($x * $x) / 4; - do { - $fTerm *= $fSqrX; - $fTerm /= ($ordK * ($ordK + $ord)); - $fResult += $fTerm; - } while ((abs($fTerm) > 1e-12) && (++$ordK < 100)); - - return $fResult; + // special cases + switch ($ord) { + case 0: + return self::besselI0($x); + case 1: + return self::besselI1($x); } - $f_2_PI = 2 * M_PI; + return self::besselI2($x, $ord); + } - $fXAbs = abs($x); - $fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs); - if (($ord & 1) && ($x < 0)) { - $fResult = -$fResult; + private static function besselI0(float $x): float + { + $ax = abs($x); + + if ($ax < 3.75) { + $y = $x / 3.75; + $y = $y * $y; + + return 1.0 + $y * (3.5156229 + $y * (3.0899424 + $y * (1.2067492 + + $y * (0.2659732 + $y * (0.360768e-1 + $y * 0.45813e-2))))); } - return $fResult; + $y = 3.75 / $ax; + + return (exp($ax) / sqrt($ax)) * (0.39894228 + $y * (0.1328592e-1 + $y * (0.225319e-2 + $y * (-0.157565e-2 + + $y * (0.916281e-2 + $y * (-0.2057706e-1 + $y * (0.2635537e-1 + + $y * (-0.1647633e-1 + $y * 0.392377e-2)))))))); + } + + private static function besselI1(float $x): float + { + $ax = abs($x); + + if ($ax < 3.75) { + $y = $x / 3.75; + $y = $y * $y; + $ans = $ax * (0.5 + $y * (0.87890594 + $y * (0.51498869 + $y * (0.15084934 + $y * (0.2658733e-1 + + $y * (0.301532e-2 + $y * 0.32411e-3)))))); + + return ($x < 0.0) ? -$ans : $ans; + } + + $y = 3.75 / $ax; + $ans = 0.2282967e-1 + $y * (-0.2895312e-1 + $y * (0.1787654e-1 - $y * 0.420059e-2)); + $ans = 0.39894228 + $y * (-0.3988024e-1 + $y * (-0.362018e-2 + $y * (0.163801e-2 + + $y * (-0.1031555e-1 + $y * $ans)))); + $ans *= exp($ax) / sqrt($ax); + + return ($x < 0.0) ? -$ans : $ans; + } + + private static function besselI2(float $x, int $ord): float + { + if ($x === 0.0) { + return 0.0; + } + + $tox = 2.0 / abs($x); + $bip = 0; + $ans = 0.0; + $bi = 1.0; + + for ($j = 2 * ($ord + (int) sqrt(40.0 * $ord)); $j > 0; --$j) { + $bim = $bip + $j * $tox * $bi; + $bip = $bi; + $bi = $bim; + + if (abs($bi) > 1.0e+12) { + $ans *= 1.0e-12; + $bi *= 1.0e-12; + $bip *= 1.0e-12; + } + + if ($j === $ord) { + $ans = $bip; + } + } + + $ans *= self::besselI0($x) / $bi; + + return ($x < 0.0 && (($ord % 2) === 1)) ? -$ans : $ans; } } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php index 62dd343a..5e8bfbf5 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php @@ -3,7 +3,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class BesselJ { @@ -15,9 +14,12 @@ class BesselJ * Excel Function: * BESSELJ(x,ord) * - * @param float $x The value at which to evaluate the function. + * NOTE: The MS Excel implementation of the BESSELJ function is still not accurate, particularly for higher order + * values with x < -8 and x > 8. This code provides a more accurate calculation + * + * @param mixed (float) $x The value at which to evaluate the function. * If x is nonnumeric, BESSELJ returns the #VALUE! error value. - * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. + * @param mixed (int) $ord The order of the Bessel function. If n is not an integer, it is truncated. * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value. * If $ord < 0, BESSELJ returns the #NUM! error value. * @@ -34,7 +36,7 @@ class BesselJ return Functions::NAN(); } - $fResult = self::calculate($x, $ord); + $fResult = self::calculate((float) $x, $ord); return (is_nan($fResult)) ? Functions::NAN() : $fResult; } @@ -44,28 +46,123 @@ class BesselJ private static function calculate(float $x, int $ord): float { - if (abs($x) <= 30) { - $fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord); - $ordK = 1; - $fSqrX = ($x * $x) / -4; - do { - $fTerm *= $fSqrX; - $fTerm /= ($ordK * ($ordK + $ord)); - $fResult += $fTerm; - } while ((abs($fTerm) > 1e-12) && (++$ordK < 100)); - - return $fResult; + // special cases + switch ($ord) { + case 0: + return self::besselJ0($x); + case 1: + return self::besselJ1($x); } - $f_PI_DIV_2 = M_PI / 2; - $f_PI_DIV_4 = M_PI / 4; + return self::besselJ2($x, $ord); + } - $fXAbs = abs($x); - $fResult = sqrt(Functions::M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4); - if (($ord & 1) && ($x < 0)) { - $fResult = -$fResult; + private static function besselJ0(float $x): float + { + $ax = abs($x); + + if ($ax < 8.0) { + $y = $x * $x; + $ans1 = 57568490574.0 + $y * (-13362590354.0 + $y * (651619640.7 + $y * (-11214424.18 + $y * + (77392.33017 + $y * (-184.9052456))))); + $ans2 = 57568490411.0 + $y * (1029532985.0 + $y * (9494680.718 + $y * (59272.64853 + $y * + (267.8532712 + $y * 1.0)))); + + return $ans1 / $ans2; } - return $fResult; + $z = 8.0 / $ax; + $y = $z * $z; + $xx = $ax - 0.785398164; + $ans1 = 1.0 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6))); + $ans2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * + (0.7621095161e-6 - $y * 0.934935152e-7))); + + return sqrt(0.636619772 / $ax) * (cos($xx) * $ans1 - $z * sin($xx) * $ans2); + } + + private static function besselJ1(float $x): float + { + $ax = abs($x); + + if ($ax < 8.0) { + $y = $x * $x; + $ans1 = $x * (72362614232.0 + $y * (-7895059235.0 + $y * (242396853.1 + $y * + (-2972611.439 + $y * (15704.48260 + $y * (-30.16036606)))))); + $ans2 = 144725228442.0 + $y * (2300535178.0 + $y * (18583304.74 + $y * (99447.43394 + $y * + (376.9991397 + $y * 1.0)))); + + return $ans1 / $ans2; + } + + $z = 8.0 / $ax; + $y = $z * $z; + $xx = $ax - 2.356194491; + + $ans1 = 1.0 + $y * (0.183105e-2 + $y * (-0.3516396496e-4 + $y * (0.2457520174e-5 + $y * (-0.240337019e-6)))); + $ans2 = 0.04687499995 + $y * (-0.2002690873e-3 + $y * (0.8449199096e-5 + $y * + (-0.88228987e-6 + $y * 0.105787412e-6))); + $ans = sqrt(0.636619772 / $ax) * (cos($xx) * $ans1 - $z * sin($xx) * $ans2); + + return ($x < 0.0) ? -$ans : $ans; + } + + private static function besselJ2(float $x, int $ord): float + { + $ax = abs($x); + if ($ax === 0.0) { + return 0.0; + } + + if ($ax > $ord) { + return self::besselj2a($ax, $ord, $x); + } + + return self::besselj2b($ax, $ord, $x); + } + + private static function besselj2a(float $ax, int $ord, float $x) + { + $tox = 2.0 / $ax; + $bjm = self::besselJ0($ax); + $bj = self::besselJ1($ax); + for ($j = 1; $j < $ord; ++$j) { + $bjp = $j * $tox * $bj - $bjm; + $bjm = $bj; + $bj = $bjp; + } + $ans = $bj; + + return ($x < 0.0 && ($ord % 2) == 1) ? -$ans : $ans; + } + + private static function besselj2b(float $ax, int $ord, float $x) + { + $tox = 2.0 / $ax; + $jsum = false; + $bjp = $ans = $sum = 0.0; + $bj = 1.0; + for ($j = 2 * ($ord + (int) sqrt(40.0 * $ord)); $j > 0; --$j) { + $bjm = $j * $tox * $bj - $bjp; + $bjp = $bj; + $bj = $bjm; + if (abs($bj) > 1.0e+10) { + $bj *= 1.0e-10; + $bjp *= 1.0e-10; + $ans *= 1.0e-10; + $sum *= 1.0e-10; + } + if ($jsum === true) { + $sum += $bj; + } + $jsum = !$jsum; + if ($j === $ord) { + $ans = $bjp; + } + } + $sum = 2.0 * $sum - $bj; + $ans /= $sum; + + return ($x < 0.0 && ($ord % 2) === 1) ? -$ans : $ans; } } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php index f64f38b0..ff32b78a 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php @@ -15,9 +15,9 @@ class BesselK * Excel Function: * BESSELK(x,ord) * - * @param float $x The value at which to evaluate the function. + * @param mixed (float) $x The value at which to evaluate the function. * If x is nonnumeric, BESSELK returns the #VALUE! error value. - * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. + * @param mixed (int) $ord The order of the Bessel function. If n is not an integer, it is truncated. * If $ord is nonnumeric, BESSELK returns the #VALUE! error value. * If $ord < 0, BESSELK returns the #NUM! error value. * @@ -29,22 +29,13 @@ class BesselK $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); if ((is_numeric($x)) && (is_numeric($ord))) { - if (($ord < 0) || ($x == 0.0)) { + $ord = (int) floor($ord); + $x = (float) $x; + if (($ord < 0) || ($x <= 0.0)) { return Functions::NAN(); } - switch (floor($ord)) { - case 0: - $fBk = self::besselK0($x); - - break; - case 1: - $fBk = self::besselK1($x); - - break; - default: - $fBk = self::besselK2($x, $ord); - } + $fBk = self::calculate($x, $ord); return (is_nan($fBk)) ? Functions::NAN() : $fBk; } @@ -52,38 +43,51 @@ class BesselK return Functions::VALUE(); } - private static function besselK0(float $fNum): float + private static function calculate($x, $ord): float { - if ($fNum <= 2) { - $fNum2 = $fNum * 0.5; + // special cases + switch (floor($ord)) { + case 0: + return self::besselK0($x); + case 1: + return self::besselK1($x); + } + + return self::besselK2($x, $ord); + } + + private static function besselK0(float $x): float + { + if ($x <= 2) { + $fNum2 = $x * 0.5; $y = ($fNum2 * $fNum2); - return -log($fNum2) * BesselI::BESSELI($fNum, 0) + + return -log($fNum2) * BesselI::BESSELI($x, 0) + (-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y * (0.10750e-3 + $y * 0.74e-5)))))); } - $y = 2 / $fNum; + $y = 2 / $x; - return exp(-$fNum) / sqrt($fNum) * + return exp(-$x) / sqrt($x) * (1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y * (0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3)))))); } - private static function besselK1(float $fNum): float + private static function besselK1(float $x): float { - if ($fNum <= 2) { - $fNum2 = $fNum * 0.5; + if ($x <= 2) { + $fNum2 = $x * 0.5; $y = ($fNum2 * $fNum2); - return log($fNum2) * BesselI::BESSELI($fNum, 1) + + return log($fNum2) * BesselI::BESSELI($x, 1) + (1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y * - (-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum; + (-0.110404e-2 + $y * (-0.4686e-4))))))) / $x; } - $y = 2 / $fNum; + $y = 2 / $x; - return exp(-$fNum) / sqrt($fNum) * + return exp(-$x) / sqrt($x) * (1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y * (0.325614e-2 + $y * (-0.68245e-3))))))); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php index 3bda914c..09694381 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php @@ -14,11 +14,11 @@ class BesselY * Excel Function: * BESSELY(x,ord) * - * @param float $x The value at which to evaluate the function. - * If x is nonnumeric, BESSELY returns the #VALUE! error value. - * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELY returns the #VALUE! error value. - * If $ord < 0, BESSELY returns the #NUM! error value. + * @param mixed (float) $x The value at which to evaluate the function. + * If x is nonnumeric, BESSELY returns the #VALUE! error value. + * @param mixed (int) $ord The order of the Bessel function. If n is not an integer, it is truncated. + * If $ord is nonnumeric, BESSELY returns the #VALUE! error value. + * If $ord < 0, BESSELY returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ @@ -28,22 +28,13 @@ class BesselY $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); if ((is_numeric($x)) && (is_numeric($ord))) { - if (($ord < 0) || ($x == 0.0)) { + $ord = (int) floor($ord); + $x = (float) $x; + if (($ord < 0) || ($x <= 0.0)) { return Functions::NAN(); } - switch (floor($ord)) { - case 0: - $fBy = self::besselY0($x); - - break; - case 1: - $fBy = self::besselY1($x); - - break; - default: - $fBy = self::besselY2($x, $ord); - } + $fBy = self::calculate($x, $ord); return (is_nan($fBy)) ? Functions::NAN() : $fBy; } @@ -51,46 +42,66 @@ class BesselY return Functions::VALUE(); } - private static function besselY0(float $fNum): float + private static function calculate($x, $ord): float { - if ($fNum < 8.0) { - $y = ($fNum * $fNum); - $f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * + // special cases + switch (floor($ord)) { + case 0: + return self::besselY0($x); + case 1: + return self::besselY1($x); + } + + return self::besselY2($x, $ord); + } + + private static function besselY0(float $x): float + { + if ($x < 8.0) { + $y = ($x * $x); + $ans1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733)))); - $f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * + $ans2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y)))); - return $f1 / $f2 + 0.636619772 * BesselJ::BESSELJ($fNum, 0) * log($fNum); + return $ans1 / $ans2 + 0.636619772 * BesselJ::BESSELJ($x, 0) * log($x); } - $z = 8.0 / $fNum; + $z = 8.0 / $x; $y = ($z * $z); - $xx = $fNum - 0.785398164; - $f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6))); - $f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * + $xx = $x - 0.785398164; + $ans1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6))); + $ans2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7)))); - return sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2); + return sqrt(0.636619772 / $x) * (sin($xx) * $ans1 + $z * cos($xx) * $ans2); } - private static function besselY1(float $fNum): float + private static function besselY1(float $x): float { - if ($fNum < 8.0) { - $y = ($fNum * $fNum); - $f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * + if ($x < 8.0) { + $y = ($x * $x); + $ans1 = $x * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y * (-0.4237922726e7 + $y * 0.8511937935e4))))); - $f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y * + $ans2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y * (0.1020426050e6 + $y * (0.3549632885e3 + $y))))); - return $f1 / $f2 + 0.636619772 * (BesselJ::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum); + return ($ans1 / $ans2) + 0.636619772 * (BesselJ::BESSELJ($x, 1) * log($x) - 1 / $x); } - return sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491); + $z = 8.0 / $x; + $y = $z * $z; + $xx = $x - 2.356194491; + $ans1 = 1.0 + $y * (0.183105e-2 + $y * (-0.3516396496e-4 + $y * (0.2457520174e-5 + $y * (-0.240337019e-6)))); + $ans2 = 0.04687499995 + $y * (-0.2002690873e-3 + $y * (0.8449199096e-5 + $y * + (-0.88228987e-6 + $y * 0.105787412e-6))); + + return sqrt(0.636619772 / $x) * (sin($xx) * $ans1 + $z * cos($xx) * $ans2); } - private static function besselY2(float $x, int $ord) + private static function besselY2(float $x, int $ord): float { - $fTox = 2 / $x; + $fTox = 2.0 / $x; $fBym = self::besselY0($x); $fBy = self::besselY1($x); for ($n = 1; $n < $ord; ++$n) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php index 8fff98af..5b6ba045 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php @@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase; class BesselITest extends TestCase { - const BESSEL_PRECISION = 1E-8; + const BESSEL_PRECISION = 1E-9; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php index 27123a26..23ad3539 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php @@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase; class BesselKTest extends TestCase { - const BESSEL_PRECISION = 1E-8; + const BESSEL_PRECISION = 1E-12; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php index ab55f0ac..4422ad50 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php @@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase; class BesselYTest extends TestCase { - const BESSEL_PRECISION = 1E-8; + const BESSEL_PRECISION = 1E-12; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php index e7907384..8c637f9a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php @@ -1,10 +1,10 @@ Date: Wed, 24 Mar 2021 20:05:32 +0100 Subject: [PATCH 132/187] Csv reader refactor infer delimiter (#1948) * Refactor delimiter inference for CSV file reading into a separate class --- src/PhpSpreadsheet/Reader/Csv.php | 103 +------------- src/PhpSpreadsheet/Reader/Csv/Delimiter.php | 144 ++++++++++++++++++++ 2 files changed, 150 insertions(+), 97 deletions(-) create mode 100644 src/PhpSpreadsheet/Reader/Csv/Delimiter.php diff --git a/src/PhpSpreadsheet/Reader/Csv.php b/src/PhpSpreadsheet/Reader/Csv.php index 92b0f6ac..dc746735 100644 --- a/src/PhpSpreadsheet/Reader/Csv.php +++ b/src/PhpSpreadsheet/Reader/Csv.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader; use InvalidArgumentException; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Reader\Csv\Delimiter; use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -138,118 +139,26 @@ class Csv extends BaseReader return; } - $potentialDelimiters = [',', ';', "\t", '|', ':', ' ', '~']; - $counts = []; - foreach ($potentialDelimiters as $delimiter) { - $counts[$delimiter] = []; - } - - // Count how many times each of the potential delimiters appears in each line - $numberLines = 0; - while (($line = $this->getNextLine()) !== false && (++$numberLines < 1000)) { - $countLine = []; - for ($i = strlen($line) - 1; $i >= 0; --$i) { - $char = $line[$i]; - if (isset($counts[$char])) { - if (!isset($countLine[$char])) { - $countLine[$char] = 0; - } - ++$countLine[$char]; - } - } - foreach ($potentialDelimiters as $delimiter) { - $counts[$delimiter][] = $countLine[$delimiter] - ?? 0; - } - } + $inferenceEngine = new Delimiter($this->fileHandle, $this->escapeCharacter, $this->enclosure); // If number of lines is 0, nothing to infer : fall back to the default - if ($numberLines === 0) { - $this->delimiter = reset($potentialDelimiters); + if ($inferenceEngine->linesCounted() === 0) { + $this->delimiter = $inferenceEngine->getDefaultDelimiter(); $this->skipBOM(); return; } - // Calculate the mean square deviations for each delimiter (ignoring delimiters that haven't been found consistently) - $meanSquareDeviations = []; - $middleIdx = floor(($numberLines - 1) / 2); - - foreach ($potentialDelimiters as $delimiter) { - $series = $counts[$delimiter]; - sort($series); - - $median = ($numberLines % 2) - ? $series[$middleIdx] - : ($series[$middleIdx] + $series[$middleIdx + 1]) / 2; - - if ($median === 0) { - continue; - } - - $meanSquareDeviations[$delimiter] = array_reduce( - $series, - function ($sum, $value) use ($median) { - return $sum + ($value - $median) ** 2; - } - ) / count($series); - } - - // ... and pick the delimiter with the smallest mean square deviation (in case of ties, the order in potentialDelimiters is respected) - $min = INF; - foreach ($potentialDelimiters as $delimiter) { - if (!isset($meanSquareDeviations[$delimiter])) { - continue; - } - - if ($meanSquareDeviations[$delimiter] < $min) { - $min = $meanSquareDeviations[$delimiter]; - $this->delimiter = $delimiter; - } - } + $this->delimiter = $inferenceEngine->infer(); // If no delimiter could be detected, fall back to the default if ($this->delimiter === null) { - $this->delimiter = reset($potentialDelimiters); + $this->delimiter = $inferenceEngine->getDefaultDelimiter(); } $this->skipBOM(); } - /** - * Get the next full line from the file. - * - * @return false|string - */ - private function getNextLine() - { - $line = ''; - $enclosure = ($this->escapeCharacter === '' ? '' - : ('(?escapeCharacter, '/') . ')')) - . preg_quote($this->enclosure, '/'); - - do { - // Get the next line in the file - $newLine = fgets($this->fileHandle); - - // Return false if there is no next line - if ($newLine === false) { - return false; - } - - // Add the new line to the line passed in - $line = $line . $newLine; - - // Drop everything that is enclosed to avoid counting false positives in enclosures - $line = preg_replace('/(' . $enclosure . '.*' . $enclosure . ')/Us', '', $line); - - // See if we have any enclosures left in the line - // if we still have an enclosure then we need to read the next line as well - } while (preg_match('/(' . $enclosure . ')/', $line) > 0); - - return $line; - } - /** * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). * diff --git a/src/PhpSpreadsheet/Reader/Csv/Delimiter.php b/src/PhpSpreadsheet/Reader/Csv/Delimiter.php new file mode 100644 index 00000000..eb62c9ac --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Csv/Delimiter.php @@ -0,0 +1,144 @@ +fileHandle = $fileHandle; + $this->escapeCharacter = $escapeCharacter; + $this->enclosure = $enclosure; + + $this->countPotentialDelimiters(); + } + + public function getDefaultDelimiter(): string + { + return self::POTENTIAL_DELIMETERS[0]; + } + + public function linesCounted(): int + { + return $this->numberLines; + } + + protected function countPotentialDelimiters(): void + { + $this->counts = array_fill_keys(self::POTENTIAL_DELIMETERS, []); + $delimiterKeys = array_flip(self::POTENTIAL_DELIMETERS); + + // Count how many times each of the potential delimiters appears in each line + $this->numberLines = 0; + while (($line = $this->getNextLine()) !== false && (++$this->numberLines < 1000)) { + $this->countDelimiterValues($line, $delimiterKeys); + } + } + + protected function countDelimiterValues(string $line, array $delimiterKeys): void + { + $splitString = str_split($line, 1); + if (!is_array($splitString)) { + return; + } + + $distribution = array_count_values($splitString); + $countLine = array_intersect_key($distribution, $delimiterKeys); + + foreach (self::POTENTIAL_DELIMETERS as $delimiter) { + $this->counts[$delimiter][] = $countLine[$delimiter] ?? 0; + } + } + + public function infer(): ?string + { + // Calculate the mean square deviations for each delimiter + // (ignoring delimiters that haven't been found consistently) + $meanSquareDeviations = []; + $middleIdx = floor(($this->numberLines - 1) / 2); + + foreach (self::POTENTIAL_DELIMETERS as $delimiter) { + $series = $this->counts[$delimiter]; + sort($series); + + $median = ($this->numberLines % 2) + ? $series[$middleIdx] + : ($series[$middleIdx] + $series[$middleIdx + 1]) / 2; + + if ($median === 0) { + continue; + } + + $meanSquareDeviations[$delimiter] = array_reduce( + $series, + function ($sum, $value) use ($median) { + return $sum + ($value - $median) ** 2; + } + ) / count($series); + } + + // ... and pick the delimiter with the smallest mean square deviation + // (in case of ties, the order in potentialDelimiters is respected) + $min = INF; + foreach (self::POTENTIAL_DELIMETERS as $delimiter) { + if (!isset($meanSquareDeviations[$delimiter])) { + continue; + } + + if ($meanSquareDeviations[$delimiter] < $min) { + $min = $meanSquareDeviations[$delimiter]; + $this->delimiter = $delimiter; + } + } + + return $this->delimiter; + } + + /** + * Get the next full line from the file. + * + * @return false|string + */ + public function getNextLine() + { + $line = ''; + $enclosure = ($this->escapeCharacter === '' ? '' + : ('(?escapeCharacter, '/') . ')')) + . preg_quote($this->enclosure, '/'); + + do { + // Get the next line in the file + $newLine = fgets($this->fileHandle); + + // Return false if there is no next line + if ($newLine === false) { + return false; + } + + // Add the new line to the line passed in + $line = $line . $newLine; + + // Drop everything that is enclosed to avoid counting false positives in enclosures + $line = preg_replace('/(' . $enclosure . '.*' . $enclosure . ')/Us', '', $line); + + // See if we have any enclosures left in the line + // if we still have an enclosure then we need to read the next line as well + } while (preg_match('/(' . $enclosure . ')/', $line) > 0); + + return $line; + } +} From f51c19c1255972047f33451a510905dab5862677 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Thu, 25 Mar 2021 20:54:55 +0100 Subject: [PATCH 133/187] First steps toward refactoring Excel's Statistical Distributions (#1949) * First steps toward refactoring Statistical Distributions into smaller classes: BETA() and GAMMA() (and related functions) to start with... they all need a lot of tidying up, and more testing; but it's a start * Add basic datatype validations to Beta and Gamma Excel function implementations * Switch to using a trait with the validation methods to provide easier sharing between distribution classes * Additional unit tests for Beta and Gamma functions, including unhappy path for validations * Extract ChiSquared functions * Additional argument validation checks with unit tests for Chi Squared functions * Extract Fisher * Move MEDIAN() and MODE() to the Averages class * Extract filters for Median and Mode for common usage --- .../Calculation/Calculation.php | 44 +- .../Calculation/Database/DAverage.php | 2 +- .../Calculation/Financial/Amortization.php | 16 +- .../Calculation/Financial/Coupons.php | 14 +- .../Calculation/Financial/Depreciation.php | 20 +- .../Calculation/Financial/Dollar.php | 8 +- .../Calculation/Financial/InterestRate.php | 8 +- .../Financial/Securities/Price.php | 22 +- .../Calculation/Financial/TreasuryBill.php | 6 +- .../Calculation/LookupRef/Address.php | 6 +- .../Calculation/LookupRef/Indirect.php | 2 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 2 +- .../Calculation/Statistical.php | 838 ++---------------- .../Calculation/Statistical/Averages.php | 130 ++- .../Calculation/Statistical/Confidence.php | 6 +- .../Distributions/BaseValidations.php | 36 + .../Statistical/Distributions/Beta.php | 263 ++++++ .../Statistical/Distributions/ChiSquared.php | 127 +++ .../Statistical/Distributions/Fisher.php | 63 ++ .../Statistical/Distributions/Gamma.php | 129 +++ .../Statistical/Distributions/GammaBase.php | 377 ++++++++ .../Calculation/Statistical/Permutations.php | 4 +- .../Statistical/StandardDeviations.php | 8 +- .../Calculation/Statistical/Trends.php | 14 +- .../Calculation/TextData/CaseConvert.php | 6 +- .../Calculation/TextData/CharacterConvert.php | 4 +- .../Calculation/TextData/Extract.php | 14 +- .../Calculation/TextData/Format.php | 14 +- .../Calculation/TextData/Replace.php | 16 +- .../Calculation/TextData/Search.php | 12 +- .../Calculation/TextData/Text.php | 6 +- .../Calculation/TextData/Trim.php | 4 +- .../data/Calculation/Statistical/BETADIST.php | 44 + .../data/Calculation/Statistical/BETAINV.php | 44 + .../data/Calculation/Statistical/CHIDIST.php | 12 +- tests/data/Calculation/Statistical/CHIINV.php | 18 +- tests/data/Calculation/Statistical/FISHER.php | 10 +- .../Calculation/Statistical/FISHERINV.php | 4 + tests/data/Calculation/Statistical/GAMMA.php | 4 +- .../Calculation/Statistical/GAMMADIST.php | 32 + .../data/Calculation/Statistical/GAMMAINV.php | 30 +- .../data/Calculation/Statistical/GAMMALN.php | 6 +- tests/data/Calculation/TextData/FIND.php | 5 + tests/data/Calculation/TextData/SEARCH.php | 5 + 44 files changed, 1548 insertions(+), 887 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index c5dbaa53..80a6fbcc 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -328,17 +328,17 @@ class Calculation ], 'AVEDEV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Averages::class, 'AVEDEV'], + 'functionCall' => [Statistical\Averages::class, 'averageDeviations'], 'argumentCount' => '1+', ], 'AVERAGE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Averages::class, 'AVERAGE'], + 'functionCall' => [Statistical\Averages::class, 'average'], 'argumentCount' => '1+', ], 'AVERAGEA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Averages::class, 'AVERAGEA'], + 'functionCall' => [Statistical\Averages::class, 'averageA'], 'argumentCount' => '1+', ], 'AVERAGEIF' => [ @@ -383,7 +383,7 @@ class Calculation ], 'BETADIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'BETADIST'], + 'functionCall' => [Statistical\Distributions\Beta::class, 'distribution'], 'argumentCount' => '3-5', ], 'BETA.DIST' => [ @@ -393,12 +393,12 @@ class Calculation ], 'BETAINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'BETAINV'], + 'functionCall' => [Statistical\Distributions\Beta::class, 'inverse'], 'argumentCount' => '3-5', ], 'BETA.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'BETAINV'], + 'functionCall' => [Statistical\Distributions\Beta::class, 'inverse'], 'argumentCount' => '3-5', ], 'BIN2DEC' => [ @@ -488,7 +488,7 @@ class Calculation ], 'CHIDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CHIDIST'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'], 'argumentCount' => '2', ], 'CHISQ.DIST' => [ @@ -498,12 +498,12 @@ class Calculation ], 'CHISQ.DIST.RT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CHIDIST'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'], 'argumentCount' => '2', ], 'CHIINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CHIINV'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'], 'argumentCount' => '2', ], 'CHISQ.INV' => [ @@ -513,7 +513,7 @@ class Calculation ], 'CHISQ.INV.RT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CHIINV'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'], 'argumentCount' => '2', ], 'CHITEST' => [ @@ -1055,12 +1055,12 @@ class Calculation ], 'FISHER' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'FISHER'], + 'functionCall' => [Statistical\Distributions\Fisher::class, 'distribution'], 'argumentCount' => '1', ], 'FISHERINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'FISHERINV'], + 'functionCall' => [Statistical\Distributions\Fisher::class, 'inverse'], 'argumentCount' => '1', ], 'FIXED' => [ @@ -1147,37 +1147,37 @@ class Calculation ], 'GAMMA' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMAFunction'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'gamma'], 'argumentCount' => '1', ], 'GAMMADIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMADIST'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'distribution'], 'argumentCount' => '4', ], 'GAMMA.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMADIST'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'distribution'], 'argumentCount' => '4', ], 'GAMMAINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMAINV'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'inverse'], 'argumentCount' => '3', ], 'GAMMA.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMAINV'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'inverse'], 'argumentCount' => '3', ], 'GAMMALN' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMALN'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'ln'], 'argumentCount' => '1', ], 'GAMMALN.PRECISE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'GAMMALN'], + 'functionCall' => [Statistical\Distributions\Gamma::class, 'ln'], 'argumentCount' => '1', ], 'GAUSS' => [ @@ -1646,7 +1646,7 @@ class Calculation ], 'MEDIAN' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MEDIAN'], + 'functionCall' => [Statistical\Averages::class, 'median'], 'argumentCount' => '1+', ], 'MEDIANIF' => [ @@ -1706,7 +1706,7 @@ class Calculation ], 'MODE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MODE'], + 'functionCall' => [Statistical\Averages::class, 'mode'], 'argumentCount' => '1+', ], 'MODE.MULT' => [ @@ -1716,7 +1716,7 @@ class Calculation ], 'MODE.SNGL' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'MODE'], + 'functionCall' => [Statistical\Averages::class, 'mode'], 'argumentCount' => '1+', ], 'MONTH' => [ diff --git a/src/PhpSpreadsheet/Calculation/Database/DAverage.php b/src/PhpSpreadsheet/Calculation/Database/DAverage.php index 738cb78e..e30842dc 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DAverage.php +++ b/src/PhpSpreadsheet/Calculation/Database/DAverage.php @@ -38,7 +38,7 @@ class DAverage extends DatabaseAbstract return null; } - return Averages::AVERAGE( + return Averages::average( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php index 76be7e12..7bb7fb40 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php @@ -22,13 +22,13 @@ class Amortization * Excel Function: * AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis]) * - * @param float $cost The cost of the asset + * @param mixed (float) $cost The cost of the asset * @param mixed $purchased Date of the purchase of the asset * @param mixed $firstPeriod Date of the end of the first period * @param mixed $salvage The salvage value at the end of the life of the asset - * @param float $period The period - * @param float $rate Rate of depreciation - * @param int $basis The type of day count to use. + * @param mixed (float) $period The period + * @param mixed (float) $rate Rate of depreciation + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -88,13 +88,13 @@ class Amortization * Excel Function: * AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis]) * - * @param float $cost The cost of the asset + * @param mixed (float) $cost The cost of the asset * @param mixed $purchased Date of the purchase of the asset * @param mixed $firstPeriod Date of the end of the first period * @param mixed $salvage The salvage value at the end of the life of the asset - * @param float $period The period - * @param float $rate Rate of depreciation - * @param int $basis The type of day count to use. + * @param mixed (float) $period The period + * @param mixed (float) $rate Rate of depreciation + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php index 835ef633..d0efd689 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -29,12 +29,12 @@ class Coupons * 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 $frequency the number of coupon payments per year. + * @param mixed (int) $frequency the number of coupon payments per year. * Valid frequency values are: * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -88,7 +88,7 @@ class Coupons * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -153,7 +153,7 @@ class Coupons * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -211,7 +211,7 @@ class Coupons * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -260,7 +260,7 @@ class Coupons * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -309,7 +309,7 @@ class Coupons * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 diff --git a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php index 9236b4d4..173e29bb 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php @@ -20,14 +20,14 @@ class Depreciation * Excel Function: * DB(cost,salvage,life,period[,month]) * - * @param float $cost Initial cost of the asset - * @param float $salvage Value at the end of the depreciation. + * @param mixed (float) $cost Initial cost of the asset + * @param mixed (float) $salvage Value at the end of the depreciation. * (Sometimes called the salvage value of the asset) - * @param int $life Number of periods over which the asset is depreciated. + * @param mixed (int) $life Number of periods over which the asset is depreciated. * (Sometimes called the useful life of the asset) - * @param int $period The period for which you want to calculate the + * @param mixed (int) $period The period for which you want to calculate the * depreciation. Period must use the same units as life. - * @param int $month Number of months in the first year. If month is omitted, + * @param mixed (int) $month Number of months in the first year. If month is omitted, * it defaults to 12. * * @return float|string @@ -85,14 +85,14 @@ class Depreciation * Excel Function: * DDB(cost,salvage,life,period[,factor]) * - * @param float $cost Initial cost of the asset - * @param float $salvage Value at the end of the depreciation. + * @param mixed (float) $cost Initial cost of the asset + * @param mixed (float) $salvage Value at the end of the depreciation. * (Sometimes called the salvage value of the asset) - * @param int $life Number of periods over which the asset is depreciated. + * @param mixed (int) $life Number of periods over which the asset is depreciated. * (Sometimes called the useful life of the asset) - * @param int $period The period for which you want to calculate the + * @param mixed (int) $period The period for which you want to calculate the * depreciation. Period must use the same units as life. - * @param float $factor The rate at which the balance declines. + * @param mixed (float) $factor The rate at which the balance declines. * If factor is omitted, it is assumed to be 2 (the * double-declining balance method). * diff --git a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php index e85b00c6..36326a60 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php @@ -16,8 +16,8 @@ class Dollar * Excel Function: * DOLLARDE(fractional_dollar,fraction) * - * @param float $fractionalDollar Fractional Dollar - * @param int $fraction Fraction + * @param mixed (float) $fractionalDollar Fractional Dollar + * @param mixed (int) $fraction Fraction * * @return float|string */ @@ -52,8 +52,8 @@ class Dollar * Excel Function: * DOLLARFR(decimal_dollar,fraction) * - * @param float $decimalDollar Decimal Dollar - * @param int $fraction Fraction + * @param mixed (float) $decimalDollar Decimal Dollar + * @param mixed (int) $fraction Fraction * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php index be7e6fd7..04b43e32 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php +++ b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php @@ -15,8 +15,8 @@ class InterestRate * Excel Function: * EFFECT(nominal_rate,npery) * - * @param float $nominalRate Nominal interest rate - * @param int $periodsPerYear Number of compounding payments per year + * @param mixed (float) $nominalRate Nominal interest rate + * @param mixed (int) $periodsPerYear Number of compounding payments per year * * @return float|string */ @@ -43,8 +43,8 @@ class InterestRate * * Returns the nominal interest rate given the effective rate and the number of compounding payments per year. * - * @param float $effectiveRate Effective interest rate - * @param int $periodsPerYear Number of compounding payments per year + * @param mixed (float) $effectiveRate Effective interest rate + * @param mixed (int) $periodsPerYear Number of compounding payments per year * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php index a5f0fb46..14be7f84 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php @@ -20,14 +20,14 @@ class Price extends BaseValidations * is traded to the buyer. * @param mixed $maturity The security's maturity date. * The maturity date is the date when the security expires. - * @param float $rate the security's annual coupon rate - * @param float $yield the security's annual yield - * @param float $redemption The number of coupon payments per year. + * @param mixed (float) $rate the security's annual coupon rate + * @param mixed (float) $yield the security's annual yield + * @param mixed (float) $redemption The number of coupon payments per year. * For annual payments, frequency = 1; * for semiannual, frequency = 2; * for quarterly, frequency = 4. - * @param int $frequency - * @param int $basis The type of day count to use. + * @param mixed (int) $frequency + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -87,9 +87,9 @@ class Price extends BaseValidations * is traded to the buyer. * @param mixed $maturity The security's maturity date. * The maturity date is the date when the security expires. - * @param float $discount The security's discount rate - * @param float $redemption The security's redemption value per $100 face value - * @param int $basis The type of day count to use. + * @param mixed (float) $discount The security's discount rate + * @param mixed (float) $redemption The security's redemption value per $100 face value + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -137,9 +137,9 @@ class Price extends BaseValidations * @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 float $rate The security's interest rate at date of issue - * @param float $yield The security's annual yield - * @param int $basis The type of day count to use. + * @param mixed (float) $rate The security's interest rate at date of issue + * @param mixed (float) $yield The security's annual yield + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 diff --git a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php index 8f8fa530..3177124a 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php +++ b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php @@ -17,7 +17,7 @@ class TreasuryBill * 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 (int) $discount The Treasury bill's discount rate * * @return float|string Result, or a string containing an error */ @@ -65,7 +65,7 @@ class TreasuryBill * 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 (int) $discount The Treasury bill's discount rate * * @return float|string Result, or a string containing an error */ @@ -117,7 +117,7 @@ class TreasuryBill * 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 (int) $price The Treasury bill's price per $100 face value * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php index 53c9c9d8..daaebea2 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php @@ -25,15 +25,15 @@ class Address * * @param mixed $row Row number to use in the cell reference * @param mixed $column Column number to use in the cell reference - * @param int $relativity Flag indicating the type of reference to return + * @param mixed (int) $relativity Flag indicating the type of reference to return * 1 or omitted Absolute * 2 Absolute row; relative column * 3 Relative row; absolute column * 4 Relative - * @param bool $referenceStyle A logical value that specifies the A1 or R1C1 reference style. + * @param mixed (bool) $referenceStyle A logical value that specifies the A1 or R1C1 reference style. * TRUE or omitted ADDRESS returns an A1-style reference * FALSE ADDRESS returns an R1C1-style reference - * @param string $sheetName Optional Name of worksheet to use + * @param mixed (string) $sheetName Optional Name of worksheet to use * * @return string */ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php b/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php index 690b32e4..c34dd965 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php @@ -21,7 +21,7 @@ class Indirect * NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010 * * @param null|array|string $cellAddress $cellAddress The cell address of the current cell (containing this formula) - * @param Cell $pCell The current cell (containing this formula) + * @param null|Cell $pCell The current cell (containing this formula) * * @return array|string An array containing a cell or range of cells, or a string on error * diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index f3d8351d..94850906 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -1156,7 +1156,7 @@ class MathTrig $aArgs = self::filterFormulaArgs($cellReference, $aArgs); switch ($subtotal) { case 1: - return Statistical\Averages::AVERAGE($aArgs); + return Statistical\Averages::average($aArgs); case 2: return Statistical\Counts::COUNT($aArgs); case 3: diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 8a9e3fea..c8e084b5 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -12,411 +12,15 @@ use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Permutations; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\StandardDeviations; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Trends; use PhpOffice\PhpSpreadsheet\Calculation\Statistical\Variances; -use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend; class Statistical { const LOG_GAMMA_X_MAX_VALUE = 2.55e305; - const XMININ = 2.23e-308; const EPS = 2.22e-16; const MAX_VALUE = 1.2e308; const MAX_ITERATIONS = 256; const SQRT2PI = 2.5066282746310005024157652848110452530069867406099; - /** - * Incomplete beta function. - * - * @author Jaco van Kooten - * @author Paul Meagher - * - * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992). - * - * @param mixed $x require 0<=x<=1 - * @param mixed $p require p>0 - * @param mixed $q require q>0 - * - * @return float 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow - */ - private static function incompleteBeta($x, $p, $q) - { - if ($x <= 0.0) { - return 0.0; - } elseif ($x >= 1.0) { - return 1.0; - } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) { - return 0.0; - } - $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x)); - if ($x < ($p + 1.0) / ($p + $q + 2.0)) { - return $beta_gam * self::betaFraction($x, $p, $q) / $p; - } - - return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q); - } - - // Function cache for logBeta function - private static $logBetaCacheP = 0.0; - - private static $logBetaCacheQ = 0.0; - - private static $logBetaCacheResult = 0.0; - - /** - * The natural logarithm of the beta function. - * - * @param mixed $p require p>0 - * @param mixed $q require q>0 - * - * @return float 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow - * - * @author Jaco van Kooten - */ - private static function logBeta($p, $q) - { - if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) { - self::$logBetaCacheP = $p; - self::$logBetaCacheQ = $q; - if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) { - self::$logBetaCacheResult = 0.0; - } else { - self::$logBetaCacheResult = self::logGamma($p) + self::logGamma($q) - self::logGamma($p + $q); - } - } - - return self::$logBetaCacheResult; - } - - /** - * Evaluates of continued fraction part of incomplete beta function. - * Based on an idea from Numerical Recipes (W.H. Press et al, 1992). - * - * @author Jaco van Kooten - * - * @param mixed $x - * @param mixed $p - * @param mixed $q - * - * @return float - */ - private static function betaFraction($x, $p, $q) - { - $c = 1.0; - $sum_pq = $p + $q; - $p_plus = $p + 1.0; - $p_minus = $p - 1.0; - $h = 1.0 - $sum_pq * $x / $p_plus; - if (abs($h) < self::XMININ) { - $h = self::XMININ; - } - $h = 1.0 / $h; - $frac = $h; - $m = 1; - $delta = 0.0; - while ($m <= self::MAX_ITERATIONS && abs($delta - 1.0) > Functions::PRECISION) { - $m2 = 2 * $m; - // even index for d - $d = $m * ($q - $m) * $x / (($p_minus + $m2) * ($p + $m2)); - $h = 1.0 + $d * $h; - if (abs($h) < self::XMININ) { - $h = self::XMININ; - } - $h = 1.0 / $h; - $c = 1.0 + $d / $c; - if (abs($c) < self::XMININ) { - $c = self::XMININ; - } - $frac *= $h * $c; - // odd index for d - $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2)); - $h = 1.0 + $d * $h; - if (abs($h) < self::XMININ) { - $h = self::XMININ; - } - $h = 1.0 / $h; - $c = 1.0 + $d / $c; - if (abs($c) < self::XMININ) { - $c = self::XMININ; - } - $delta = $h * $c; - $frac *= $delta; - ++$m; - } - - return $frac; - } - - /** - * logGamma function. - * - * @version 1.1 - * - * @author Jaco van Kooten - * - * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher. - * - * The natural logarithm of the gamma function.
- * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
- * Applied Mathematics Division
- * Argonne National Laboratory
- * Argonne, IL 60439
- *

- * References: - *

    - *
  1. W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural - * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
  2. - *
  3. K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
  4. - *
  5. Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
  6. - *
- *

- *

- * From the original documentation: - *

- *

- * This routine calculates the LOG(GAMMA) function for a positive real argument X. - * Computation is based on an algorithm outlined in references 1 and 2. - * The program uses rational functions that theoretically approximate LOG(GAMMA) - * to at least 18 significant decimal digits. The approximation for X > 12 is from - * reference 3, while approximations for X < 12.0 are similar to those in reference - * 1, but are unpublished. The accuracy achieved depends on the arithmetic system, - * the compiler, the intrinsic functions, and proper selection of the - * machine-dependent constants. - *

- *

- * Error returns:
- * The program returns the value XINF for X .LE. 0.0 or when overflow would occur. - * The computation is believed to be free of underflow and overflow. - *

- * - * @return float MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305 - */ - - // Function cache for logGamma - private static $logGammaCacheResult = 0.0; - - private static $logGammaCacheX = 0.0; - - private static function logGamma($x) - { - // Log Gamma related constants - static $lg_d1 = -0.5772156649015328605195174; - static $lg_d2 = 0.4227843350984671393993777; - static $lg_d4 = 1.791759469228055000094023; - - static $lg_p1 = [ - 4.945235359296727046734888, - 201.8112620856775083915565, - 2290.838373831346393026739, - 11319.67205903380828685045, - 28557.24635671635335736389, - 38484.96228443793359990269, - 26377.48787624195437963534, - 7225.813979700288197698961, - ]; - static $lg_p2 = [ - 4.974607845568932035012064, - 542.4138599891070494101986, - 15506.93864978364947665077, - 184793.2904445632425417223, - 1088204.76946882876749847, - 3338152.967987029735917223, - 5106661.678927352456275255, - 3074109.054850539556250927, - ]; - static $lg_p4 = [ - 14745.02166059939948905062, - 2426813.369486704502836312, - 121475557.4045093227939592, - 2663432449.630976949898078, - 29403789566.34553899906876, - 170266573776.5398868392998, - 492612579337.743088758812, - 560625185622.3951465078242, - ]; - static $lg_q1 = [ - 67.48212550303777196073036, - 1113.332393857199323513008, - 7738.757056935398733233834, - 27639.87074403340708898585, - 54993.10206226157329794414, - 61611.22180066002127833352, - 36351.27591501940507276287, - 8785.536302431013170870835, - ]; - static $lg_q2 = [ - 183.0328399370592604055942, - 7765.049321445005871323047, - 133190.3827966074194402448, - 1136705.821321969608938755, - 5267964.117437946917577538, - 13467014.54311101692290052, - 17827365.30353274213975932, - 9533095.591844353613395747, - ]; - static $lg_q4 = [ - 2690.530175870899333379843, - 639388.5654300092398984238, - 41355999.30241388052042842, - 1120872109.61614794137657, - 14886137286.78813811542398, - 101680358627.2438228077304, - 341747634550.7377132798597, - 446315818741.9713286462081, - ]; - static $lg_c = [ - -0.001910444077728, - 8.4171387781295e-4, - -5.952379913043012e-4, - 7.93650793500350248e-4, - -0.002777777777777681622553, - 0.08333333333333333331554247, - 0.0057083835261, - ]; - - // Rough estimate of the fourth root of logGamma_xBig - static $lg_frtbig = 2.25e76; - static $pnt68 = 0.6796875; - - if ($x == self::$logGammaCacheX) { - return self::$logGammaCacheResult; - } - $y = $x; - if ($y > 0.0 && $y <= self::LOG_GAMMA_X_MAX_VALUE) { - if ($y <= self::EPS) { - $res = -log($y); - } elseif ($y <= 1.5) { - // --------------------- - // EPS .LT. X .LE. 1.5 - // --------------------- - if ($y < $pnt68) { - $corr = -log($y); - $xm1 = $y; - } else { - $corr = 0.0; - $xm1 = $y - 1.0; - } - if ($y <= 0.5 || $y >= $pnt68) { - $xden = 1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm1 + $lg_p1[$i]; - $xden = $xden * $xm1 + $lg_q1[$i]; - } - $res = $corr + $xm1 * ($lg_d1 + $xm1 * ($xnum / $xden)); - } else { - $xm2 = $y - 1.0; - $xden = 1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm2 + $lg_p2[$i]; - $xden = $xden * $xm2 + $lg_q2[$i]; - } - $res = $corr + $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden)); - } - } elseif ($y <= 4.0) { - // --------------------- - // 1.5 .LT. X .LE. 4.0 - // --------------------- - $xm2 = $y - 2.0; - $xden = 1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm2 + $lg_p2[$i]; - $xden = $xden * $xm2 + $lg_q2[$i]; - } - $res = $xm2 * ($lg_d2 + $xm2 * ($xnum / $xden)); - } elseif ($y <= 12.0) { - // ---------------------- - // 4.0 .LT. X .LE. 12.0 - // ---------------------- - $xm4 = $y - 4.0; - $xden = -1.0; - $xnum = 0.0; - for ($i = 0; $i < 8; ++$i) { - $xnum = $xnum * $xm4 + $lg_p4[$i]; - $xden = $xden * $xm4 + $lg_q4[$i]; - } - $res = $lg_d4 + $xm4 * ($xnum / $xden); - } else { - // --------------------------------- - // Evaluate for argument .GE. 12.0 - // --------------------------------- - $res = 0.0; - if ($y <= $lg_frtbig) { - $res = $lg_c[6]; - $ysq = $y * $y; - for ($i = 0; $i < 6; ++$i) { - $res = $res / $ysq + $lg_c[$i]; - } - $res /= $y; - $corr = log($y); - $res = $res + log(self::SQRT2PI) - 0.5 * $corr; - $res += $y * ($corr - 1.0); - } - } - } else { - // -------------------------- - // Return for bad arguments - // -------------------------- - $res = self::MAX_VALUE; - } - // ------------------------------ - // Final adjustments and return - // ------------------------------ - self::$logGammaCacheX = $x; - self::$logGammaCacheResult = $res; - - return $res; - } - - // - // Private implementation of the incomplete Gamma function - // - private static function incompleteGamma($a, $x) - { - static $max = 32; - $summer = 0; - for ($n = 0; $n <= $max; ++$n) { - $divisor = $a; - for ($i = 1; $i <= $n; ++$i) { - $divisor *= ($a + $i); - } - $summer += ($x ** $n / $divisor); - } - - return $x ** $a * exp(0 - $x) * $summer; - } - - // - // Private implementation of the Gamma function - // - private static function gamma($data) - { - if ($data == 0.0) { - return 0; - } - - static $p0 = 1.000000000190015; - static $p = [ - 1 => 76.18009172947146, - 2 => -86.50532032941677, - 3 => 24.01409824083091, - 4 => -1.231739572450155, - 5 => 1.208650973866179e-3, - 6 => -5.395239384953e-6, - ]; - - $y = $x = $data; - $tmp = $x + 5.5; - $tmp -= ($x + 0.5) * log($tmp); - - $summer = $p0; - for ($j = 1; $j <= 6; ++$j) { - $summer += ($p[$j] / ++$y); - } - - return exp(0 - $tmp + log(self::SQRT2PI * $summer / $x)); - } - /* * inverse_ncdf.php * ------------------- @@ -512,16 +116,16 @@ class Statistical * * @Deprecated 1.17.0 * - * @see Statistical\Averages::AVEDEV() - * Use the AVEDEV() method in the Statistical\Averages class instead - * * @param mixed ...$args Data values * * @return float|string + * + *@see Statistical\Averages::averageDeviations() + * Use the averageDeviations() method in the Statistical\Averages class instead */ public static function AVEDEV(...$args) { - return Averages::AVEDEV(...$args); + return Averages::averageDeviations(...$args); } /** @@ -534,8 +138,8 @@ class Statistical * * @Deprecated 1.17.0 * - * @see Statistical\Averages::AVERAGE() - * Use the AVERAGE() method in the Statistical\Averages class instead + * @see Statistical\Averages::average() + * Use the average() method in the Statistical\Averages class instead * * @param mixed ...$args Data values * @@ -543,7 +147,7 @@ class Statistical */ public static function AVERAGE(...$args) { - return Averages::AVERAGE(...$args); + return Averages::average(...$args); } /** @@ -556,16 +160,16 @@ class Statistical * * @Deprecated 1.17.0 * - * @see Statistical\Averages::AVERAGEA() - * Use the AVERAGEA() method in the Statistical\Averages class instead - * * @param mixed ...$args Data values * * @return float|string + * + *@see Statistical\Averages::averageA() + * Use the averageA() method in the Statistical\Averages class instead */ public static function AVERAGEA(...$args) { - return Averages::AVERAGEA(...$args); + return Averages::averageA(...$args); } /** @@ -597,6 +201,11 @@ class Statistical * * Returns the beta distribution. * + * @Deprecated 1.18.0 + * + *@see Statistical\Distributions\Beta::distribution() + * Use the distribution() method in the Statistical\Distributions\Beta class instead + * * @param float $value Value at which you want to evaluate the distribution * @param float $alpha Parameter to the distribution * @param float $beta Parameter to the distribution @@ -607,28 +216,7 @@ class Statistical */ public static function BETADIST($value, $alpha, $beta, $rMin = 0, $rMax = 1) { - $value = Functions::flattenSingleValue($value); - $alpha = Functions::flattenSingleValue($alpha); - $beta = Functions::flattenSingleValue($beta); - $rMin = Functions::flattenSingleValue($rMin); - $rMax = Functions::flattenSingleValue($rMax); - - if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { - if ($rMin > $rMax) { - $tmp = $rMin; - $rMin = $rMax; - $rMax = $tmp; - } - if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) { - return Functions::NAN(); - } - $value -= $rMin; - $value /= ($rMax - $rMin); - - return self::incompleteBeta($value, $alpha, $beta); - } - - return Functions::VALUE(); + return Statistical\Distributions\Beta::distribution($value, $alpha, $beta, $rMin, $rMax); } /** @@ -636,6 +224,11 @@ class Statistical * * Returns the inverse of the Beta distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Beta::inverse() + * Use the inverse() method in the Statistical\Distributions\Beta class instead + * * @param float $probability Probability at which you want to evaluate the distribution * @param float $alpha Parameter to the distribution * @param float $beta Parameter to the distribution @@ -646,44 +239,7 @@ class Statistical */ public static function BETAINV($probability, $alpha, $beta, $rMin = 0, $rMax = 1) { - $probability = Functions::flattenSingleValue($probability); - $alpha = Functions::flattenSingleValue($alpha); - $beta = Functions::flattenSingleValue($beta); - $rMin = Functions::flattenSingleValue($rMin); - $rMax = Functions::flattenSingleValue($rMax); - - if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta)) && (is_numeric($rMin)) && (is_numeric($rMax))) { - if ($rMin > $rMax) { - $tmp = $rMin; - $rMin = $rMax; - $rMax = $tmp; - } - if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { - return Functions::NAN(); - } - $a = 0; - $b = 2; - - $i = 0; - while ((($b - $a) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { - $guess = ($a + $b) / 2; - $result = self::BETADIST($guess, $alpha, $beta); - if (($result == $probability) || ($result == 0)) { - $b = $a; - } elseif ($result > $probability) { - $b = $guess; - } else { - $a = $guess; - } - } - if ($i == self::MAX_ITERATIONS) { - return Functions::NA(); - } - - return round($rMin + $guess * ($rMax - $rMin), 12); - } - - return Functions::VALUE(); + return Statistical\Distributions\Beta::inverse($probability, $alpha, $beta, $rMin, $rMax); } /** @@ -739,6 +295,11 @@ class Statistical * * Returns the one-tailed probability of the chi-squared distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\ChiSquared::distribution() + * Use the distribution() method in the Statistical\Distributions\ChiSquared class instead + * * @param float $value Value for the function * @param float $degrees degrees of freedom * @@ -746,26 +307,7 @@ class Statistical */ public static function CHIDIST($value, $degrees) { - $value = Functions::flattenSingleValue($value); - $degrees = Functions::flattenSingleValue($degrees); - - if ((is_numeric($value)) && (is_numeric($degrees))) { - $degrees = floor($degrees); - if ($degrees < 1) { - return Functions::NAN(); - } - if ($value < 0) { - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - return 1; - } - - return Functions::NAN(); - } - - return 1 - (self::incompleteGamma($degrees / 2, $value / 2) / self::gamma($degrees / 2)); - } - - return Functions::VALUE(); + return Statistical\Distributions\ChiSquared::distribution($value, $degrees); } /** @@ -773,6 +315,11 @@ class Statistical * * Returns the one-tailed probability of the chi-squared distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\ChiSquared::inverse() + * Use the inverse() method in the Statistical\Distributions\ChiSquared class instead + * * @param float $probability Probability for the function * @param float $degrees degrees of freedom * @@ -780,52 +327,7 @@ class Statistical */ public static function CHIINV($probability, $degrees) { - $probability = Functions::flattenSingleValue($probability); - $degrees = Functions::flattenSingleValue($degrees); - - if ((is_numeric($probability)) && (is_numeric($degrees))) { - $degrees = floor($degrees); - - $xLo = 100; - $xHi = 0; - - $x = $xNew = 1; - $dx = 1; - $i = 0; - - while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $result = 1 - (self::incompleteGamma($degrees / 2, $x / 2) / self::gamma($degrees / 2)); - $error = $result - $probability; - if ($error == 0.0) { - $dx = 0; - } elseif ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } - // Avoid division by zero - if ($result != 0.0) { - $dx = $error / $result; - $xNew = $x - $dx; - } - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - if ($i == self::MAX_ITERATIONS) { - return Functions::NA(); - } - - return round($x, 12); - } - - return Functions::VALUE(); + return Statistical\Distributions\ChiSquared::inverse($probability, $degrees); } /** @@ -1146,7 +648,7 @@ class Statistical // Return value $returnValue = null; - $aMean = Averages::AVERAGE($aArgs); + $aMean = Averages::average($aArgs); if ($aMean != Functions::DIV0()) { $aCount = -1; foreach ($aArgs as $k => $arg) { @@ -1214,16 +716,6 @@ class Statistical return Functions::VALUE(); } - private static function betaFunction($a, $b) - { - return (self::gamma($a) * self::gamma($b)) / self::gamma($a + $b); - } - - private static function regularizedIncompleteBeta($value, $a, $b) - { - return self::incompleteBeta($value, $a, $b) / self::betaFunction($a, $b); - } - /** * F.DIST. * @@ -1259,10 +751,12 @@ class Statistical if ($cumulative) { $adjustedValue = ($u * $value) / ($u * $value + $v); - return self::incompleteBeta($adjustedValue, $u / 2, $v / 2); + return Statistical\Distributions\Beta::incompleteBeta($adjustedValue, $u / 2, $v / 2); } - return (self::gamma(($v + $u) / 2) / (self::gamma($u / 2) * self::gamma($v / 2))) * + return (Statistical\Distributions\Gamma::gammaValue(($v + $u) / 2) / + (Statistical\Distributions\Gamma::gammaValue($u / 2) * + Statistical\Distributions\Gamma::gammaValue($v / 2))) * (($u / $v) ** ($u / 2)) * (($value ** (($u - 2) / 2)) / ((1 + ($u / $v) * $value) ** (($u + $v) / 2))); } @@ -1277,23 +771,18 @@ class Statistical * is normally distributed rather than skewed. Use this function to perform hypothesis * testing on the correlation coefficient. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Fisher::distribution() + * Use the distribution() method in the Statistical\Distributions\Fisher class instead + * * @param float $value * * @return float|string */ public static function FISHER($value) { - $value = Functions::flattenSingleValue($value); - - if (is_numeric($value)) { - if (($value <= -1) || ($value >= 1)) { - return Functions::NAN(); - } - - return 0.5 * log((1 + $value) / (1 - $value)); - } - - return Functions::VALUE(); + return Statistical\Distributions\Fisher::distribution($value); } /** @@ -1303,19 +792,18 @@ class Statistical * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then * FISHERINV(y) = x. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Fisher::inverse() + * Use the inverse() method in the Statistical\Distributions\Fisher class instead + * * @param float $value * * @return float|string */ public static function FISHERINV($value) { - $value = Functions::flattenSingleValue($value); - - if (is_numeric($value)) { - return (exp(2 * $value) - 1) / (exp(2 * $value) + 1); - } - - return Functions::VALUE(); + return Statistical\Distributions\Fisher::inverse($value); } /** @@ -1342,7 +830,12 @@ class Statistical /** * GAMMA. * - * Return the gamma function value. + * Returns the gamma function value. + * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Gamma::gamma() + * Use the gamma() method in the Statistical\Distributions\Gamma class instead * * @param float $value * @@ -1350,14 +843,7 @@ class Statistical */ public static function GAMMAFunction($value) { - $value = Functions::flattenSingleValue($value); - if (!is_numeric($value)) { - return Functions::VALUE(); - } elseif ((((int) $value) == ((float) $value)) && $value <= 0.0) { - return Functions::NAN(); - } - - return self::gamma($value); + return Statistical\Distributions\Gamma::gamma($value); } /** @@ -1365,6 +851,11 @@ class Statistical * * Returns the gamma distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Gamma::distribution() + * Use the distribution() method in the Statistical\Distributions\Gamma class instead + * * @param float $value Value at which you want to evaluate the distribution * @param float $a Parameter to the distribution * @param float $b Parameter to the distribution @@ -1374,24 +865,7 @@ class Statistical */ public static function GAMMADIST($value, $a, $b, $cumulative) { - $value = Functions::flattenSingleValue($value); - $a = Functions::flattenSingleValue($a); - $b = Functions::flattenSingleValue($b); - - if ((is_numeric($value)) && (is_numeric($a)) && (is_numeric($b))) { - if (($value < 0) || ($a <= 0) || ($b <= 0)) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return self::incompleteGamma($a, $value / $b) / self::gamma($a); - } - - return (1 / ($b ** $a * self::gamma($a))) * $value ** ($a - 1) * exp(0 - ($value / $b)); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Gamma::distribution($value, $a, $b, $cumulative); } /** @@ -1399,6 +873,11 @@ class Statistical * * Returns the inverse of the Gamma distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Gamma::inverse() + * Use the inverse() method in the Statistical\Distributions\Gamma class instead + * * @param float $probability Probability at which you want to evaluate the distribution * @param float $alpha Parameter to the distribution * @param float $beta Parameter to the distribution @@ -1407,53 +886,7 @@ class Statistical */ public static function GAMMAINV($probability, $alpha, $beta) { - $probability = Functions::flattenSingleValue($probability); - $alpha = Functions::flattenSingleValue($alpha); - $beta = Functions::flattenSingleValue($beta); - - if ((is_numeric($probability)) && (is_numeric($alpha)) && (is_numeric($beta))) { - if (($alpha <= 0) || ($beta <= 0) || ($probability < 0) || ($probability > 1)) { - return Functions::NAN(); - } - - $xLo = 0; - $xHi = $alpha * $beta * 5; - - $x = $xNew = 1; - $dx = 1024; - $i = 0; - - while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $error = self::GAMMADIST($x, $alpha, $beta, true) - $probability; - if ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } - $pdf = self::GAMMADIST($x, $alpha, $beta, false); - // Avoid division by zero - if ($pdf != 0.0) { - $dx = $error / $pdf; - $xNew = $x - $dx; - } - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - if ($i == self::MAX_ITERATIONS) { - return Functions::NA(); - } - - return $x; - } - - return Functions::VALUE(); + return Statistical\Distributions\Gamma::inverse($probability, $alpha, $beta); } /** @@ -1461,23 +894,18 @@ class Statistical * * Returns the natural logarithm of the gamma function. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Gamma::ln() + * Use the ln() method in the Statistical\Distributions\Gamma class instead + * * @param float $value * * @return float|string */ public static function GAMMALN($value) { - $value = Functions::flattenSingleValue($value); - - if (is_numeric($value)) { - if ($value <= 0) { - return Functions::NAN(); - } - - return log(self::gamma($value)); - } - - return Functions::VALUE(); + return Statistical\Distributions\Gamma::ln($value); } /** @@ -1673,7 +1101,7 @@ class Statistical public static function KURT(...$args) { $aArgs = Functions::flattenArrayIndexed($args); - $mean = Averages::AVERAGE($aArgs); + $mean = Averages::average($aArgs); $stdDev = StandardDeviations::STDEV($aArgs); if ($stdDev > 0) { @@ -1962,37 +1390,18 @@ class Statistical * Excel Function: * MEDIAN(value1[,value2[, ...]]) * + * @Deprecated 1.18.0 + * + * @see Statistical\Averages::median() + * Use the median() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string The result, or a string containing an error */ public static function MEDIAN(...$args) { - $returnValue = Functions::NAN(); - - $mArgs = []; - // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - - $mValueCount = count($mArgs); - if ($mValueCount > 0) { - sort($mArgs, SORT_NUMERIC); - $mValueCount = $mValueCount / 2; - if ($mValueCount == floor($mValueCount)) { - $returnValue = ($mArgs[$mValueCount--] + $mArgs[$mValueCount]) / 2; - } else { - $mValueCount = floor($mValueCount); - $returnValue = $mArgs[$mValueCount]; - } - } - - return $returnValue; + return Statistical\Averages::median(...$args); } /** @@ -2062,55 +1471,6 @@ class Statistical return Conditional::MINIFS(...$args); } - // - // 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) - { - $frequencyArray = []; - $index = 0; - $maxfreq = 0; - $maxfreqkey = ''; - $maxfreqdatum = ''; - foreach ($data as $datum) { - $found = false; - ++$index; - foreach ($frequencyArray as $key => $value) { - if ((string) $value['value'] == (string) $datum) { - ++$frequencyArray[$key]['frequency']; - $freq = $frequencyArray[$key]['frequency']; - if ($freq > $maxfreq) { - $maxfreq = $freq; - $maxfreqkey = $key; - $maxfreqdatum = $datum; - } elseif ($freq == $maxfreq) { - if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) { - $maxfreqkey = $key; - $maxfreqdatum = $datum; - } - } - $found = true; - - break; - } - } - if (!$found) { - $frequencyArray[] = [ - 'value' => $datum, - 'frequency' => 1, - 'index' => $index, - ]; - } - } - - if ($maxfreq <= 1) { - return Functions::NA(); - } - - return $maxfreqdatum; - } - /** * MODE. * @@ -2119,30 +1479,18 @@ class Statistical * Excel Function: * MODE(value1[,value2[, ...]]) * + * @Deprecated 1.18.0 + * + * @see Statistical\Averages::mode() + * Use the mode() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string The result, or a string containing an error */ public static function MODE(...$args) { - $returnValue = Functions::NA(); - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - - $mArgs = []; - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - - if (!empty($mArgs)) { - return self::modeCalc($mArgs); - } - - return $returnValue; + return Statistical\Averages::mode(...$args); } /** @@ -2575,7 +1923,7 @@ class Statistical public static function SKEW(...$args) { $aArgs = Functions::flattenArrayIndexed($args); - $mean = Averages::AVERAGE($aArgs); + $mean = Averages::average($aArgs); $stdDev = StandardDeviations::STDEV($aArgs); if ($stdDev === 0.0 || is_string($stdDev)) { @@ -2990,7 +2338,7 @@ class Statistical array_shift($mArgs); } - return Averages::AVERAGE($mArgs); + return Averages::average($mArgs); } return Functions::VALUE(); @@ -3142,6 +2490,6 @@ class Statistical } $n = count($dataSet); - return 1 - self::NORMSDIST((Averages::AVERAGE($dataSet) - $m0) / ($sigma / sqrt($n))); + return 1 - self::NORMSDIST((Averages::average($dataSet) - $m0) / ($sigma / sqrt($n))); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Averages.php b/src/PhpSpreadsheet/Calculation/Statistical/Averages.php index 14c9fef2..1a627e99 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Averages.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Averages.php @@ -19,14 +19,14 @@ class Averages extends AggregateBase * * @return float|string (string if result is an error) */ - public static function AVEDEV(...$args) + public static function averageDeviations(...$args) { $aArgs = Functions::flattenArrayIndexed($args); // Return value $returnValue = 0; - $aMean = self::AVERAGE(...$args); + $aMean = self::average(...$args); if ($aMean === Functions::DIV0()) { return Functions::NAN(); } elseif ($aMean === Functions::VALUE()) { @@ -68,7 +68,7 @@ class Averages extends AggregateBase * * @return float|string (string if result is an error) */ - public static function AVERAGE(...$args) + public static function average(...$args) { $returnValue = $aCount = 0; @@ -107,7 +107,7 @@ class Averages extends AggregateBase * * @return float|string (string if result is an error) */ - public static function AVERAGEA(...$args) + public static function averageA(...$args) { $returnValue = null; @@ -134,4 +134,126 @@ class Averages extends AggregateBase return Functions::DIV0(); } + + /** + * MEDIAN. + * + * Returns the median of the given numbers. The median is the number in the middle of a set of numbers. + * + * Excel Function: + * MEDIAN(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string The result, or a string containing an error + */ + public static function median(...$args) + { + $aArgs = Functions::flattenArray($args); + + $returnValue = Functions::NAN(); + + $aArgs = self::filterArguments($aArgs); + $valueCount = count($aArgs); + if ($valueCount > 0) { + sort($aArgs, SORT_NUMERIC); + $valueCount = $valueCount / 2; + if ($valueCount == floor($valueCount)) { + $returnValue = ($aArgs[$valueCount--] + $aArgs[$valueCount]) / 2; + } else { + $valueCount = floor($valueCount); + $returnValue = $aArgs[$valueCount]; + } + } + + return $returnValue; + } + + /** + * MODE. + * + * Returns the most frequently occurring, or repetitive, value in an array or range of data + * + * Excel Function: + * MODE(value1[,value2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return float|string The result, or a string containing an error + */ + public static function mode(...$args) + { + $returnValue = Functions::NA(); + + // Loop through arguments + $aArgs = Functions::flattenArray($args); + $aArgs = self::filterArguments($aArgs); + + if (!empty($aArgs)) { + return self::modeCalc($aArgs); + } + + return $returnValue; + } + + protected static function filterArguments($args) + { + return array_filter( + $args, + function ($value) { + // Is it a numeric value? + return (is_numeric($value)) && (!is_string($value)); + } + ); + } + + // + // 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) + { + $frequencyArray = []; + $index = 0; + $maxfreq = 0; + $maxfreqkey = ''; + $maxfreqdatum = ''; + foreach ($data as $datum) { + $found = false; + ++$index; + foreach ($frequencyArray as $key => $value) { + if ((string) $value['value'] == (string) $datum) { + ++$frequencyArray[$key]['frequency']; + $freq = $frequencyArray[$key]['frequency']; + if ($freq > $maxfreq) { + $maxfreq = $freq; + $maxfreqkey = $key; + $maxfreqdatum = $datum; + } elseif ($freq == $maxfreq) { + if ($frequencyArray[$key]['index'] < $frequencyArray[$maxfreqkey]['index']) { + $maxfreqkey = $key; + $maxfreqdatum = $datum; + } + } + $found = true; + + break; + } + } + + if ($found === false) { + $frequencyArray[] = [ + 'value' => $datum, + 'frequency' => 1, + 'index' => $index, + ]; + } + } + + if ($maxfreq <= 1) { + return Functions::NA(); + } + + return $maxfreqdatum; + } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php index c4c2a7dd..3147859b 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php @@ -12,9 +12,9 @@ class Confidence * * Returns the confidence interval for a population mean * - * @param float $alpha - * @param float $stdDev Standard Deviation - * @param float $size + * @param mixed (float) $alpha + * @param mixed (float) $stdDev Standard Deviation + * @param mixed (float) $size * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php new file mode 100644 index 00000000..a8ab3e89 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php @@ -0,0 +1,36 @@ +getMessage(); + } + + if ($rMin > $rMax) { + $tmp = $rMin; + $rMin = $rMax; + $rMax = $tmp; + } + if (($value < $rMin) || ($value > $rMax) || ($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax)) { + return Functions::NAN(); + } + + $value -= $rMin; + $value /= ($rMax - $rMin); + + return self::incompleteBeta($value, $alpha, $beta); + } + + /** + * BETAINV. + * + * Returns the inverse of the Beta distribution. + * + * @param mixed (float) $probability Probability at which you want to evaluate the distribution + * @param mixed (float) $alpha Parameter to the distribution + * @param mixed (float) $beta Parameter to the distribution + * @param mixed (float) $rMin Minimum value + * @param mixed (float) $rMax Maximum value + * + * @return float|string + */ + public static function inverse($probability, $alpha, $beta, $rMin = 0, $rMax = 1) + { + $probability = Functions::flattenSingleValue($probability); + $alpha = Functions::flattenSingleValue($alpha); + $beta = Functions::flattenSingleValue($beta); + $rMin = Functions::flattenSingleValue($rMin); + $rMax = Functions::flattenSingleValue($rMax); + + try { + $probability = self::validateFloat($probability); + $alpha = self::validateFloat($alpha); + $beta = self::validateFloat($beta); + $rMax = self::validateFloat($rMax); + $rMin = self::validateFloat($rMin); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($rMin > $rMax) { + $tmp = $rMin; + $rMin = $rMax; + $rMax = $tmp; + } + if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { + return Functions::NAN(); + } + + return self::calculateInverse($probability, $alpha, $beta, $rMin, $rMax); + } + + private static function calculateInverse(float $probability, float $alpha, float $beta, float $rMin, float $rMax) + { + $a = 0; + $b = 2; + + $i = 0; + while ((($b - $a) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { + $guess = ($a + $b) / 2; + $result = self::distribution($guess, $alpha, $beta); + if (($result === $probability) || ($result === 0.0)) { + $b = $a; + } elseif ($result > $probability) { + $b = $guess; + } else { + $a = $guess; + } + } + + if ($i === self::MAX_ITERATIONS) { + return Functions::NA(); + } + + return round($rMin + $guess * ($rMax - $rMin), 12); + } + + /** + * Incomplete beta function. + * + * @author Jaco van Kooten + * @author Paul Meagher + * + * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992). + * + * @param mixed $x require 0<=x<=1 + * @param mixed $p require p>0 + * @param mixed $q require q>0 + * + * @return float 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow + */ + public static function incompleteBeta(float $x, float $p, float $q): float + { + if ($x <= 0.0) { + return 0.0; + } elseif ($x >= 1.0) { + return 1.0; + } elseif (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) { + return 0.0; + } + + $beta_gam = exp((0 - self::logBeta($p, $q)) + $p * log($x) + $q * log(1.0 - $x)); + if ($x < ($p + 1.0) / ($p + $q + 2.0)) { + return $beta_gam * self::betaFraction($x, $p, $q) / $p; + } + + return 1.0 - ($beta_gam * self::betaFraction(1 - $x, $q, $p) / $q); + } + + // Function cache for logBeta function + private static $logBetaCacheP = 0.0; + + private static $logBetaCacheQ = 0.0; + + private static $logBetaCacheResult = 0.0; + + /** + * The natural logarithm of the beta function. + * + * @param mixed $p require p>0 + * @param mixed $q require q>0 + * + * @return float 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow + * + * @author Jaco van Kooten + */ + private static function logBeta(float $p, float $q): float + { + if ($p != self::$logBetaCacheP || $q != self::$logBetaCacheQ) { + self::$logBetaCacheP = $p; + self::$logBetaCacheQ = $q; + if (($p <= 0.0) || ($q <= 0.0) || (($p + $q) > self::LOG_GAMMA_X_MAX_VALUE)) { + self::$logBetaCacheResult = 0.0; + } else { + self::$logBetaCacheResult = Gamma::logGamma($p) + Gamma::logGamma($q) - Gamma::logGamma($p + $q); + } + } + + return self::$logBetaCacheResult; + } + + /** + * Evaluates of continued fraction part of incomplete beta function. + * Based on an idea from Numerical Recipes (W.H. Press et al, 1992). + * + * @author Jaco van Kooten + * + * @param mixed $x + * @param mixed $p + * @param mixed $q + */ + private static function betaFraction(float $x, float $p, float $q): float + { + $c = 1.0; + $sum_pq = $p + $q; + $p_plus = $p + 1.0; + $p_minus = $p - 1.0; + $h = 1.0 - $sum_pq * $x / $p_plus; + if (abs($h) < self::XMININ) { + $h = self::XMININ; + } + $h = 1.0 / $h; + $frac = $h; + $m = 1; + $delta = 0.0; + while ($m <= self::MAX_ITERATIONS && abs($delta - 1.0) > Functions::PRECISION) { + $m2 = 2 * $m; + // even index for d + $d = $m * ($q - $m) * $x / (($p_minus + $m2) * ($p + $m2)); + $h = 1.0 + $d * $h; + if (abs($h) < self::XMININ) { + $h = self::XMININ; + } + $h = 1.0 / $h; + $c = 1.0 + $d / $c; + if (abs($c) < self::XMININ) { + $c = self::XMININ; + } + $frac *= $h * $c; + // odd index for d + $d = -($p + $m) * ($sum_pq + $m) * $x / (($p + $m2) * ($p_plus + $m2)); + $h = 1.0 + $d * $h; + if (abs($h) < self::XMININ) { + $h = self::XMININ; + } + $h = 1.0 / $h; + $c = 1.0 + $d / $c; + if (abs($c) < self::XMININ) { + $c = self::XMININ; + } + $delta = $h * $c; + $frac *= $delta; + ++$m; + } + + return $frac; + } + + private static function betaValue(float $a, float $b): float + { + return (Gamma::gammaValue($a) * Gamma::gammaValue($b)) / + Gamma::gammaValue($a + $b); + } + + private static function regularizedIncompleteBeta(float $value, float $a, float $b): float + { + return self::incompleteBeta($value, $a, $b) / self::betaValue($a, $b); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php new file mode 100644 index 00000000..2d5e4496 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -0,0 +1,127 @@ +getMessage(); + } + + if ($degrees < 1) { + return Functions::NAN(); + } + if ($value < 0) { + if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { + return 1; + } + + return Functions::NAN(); + } + + return 1 - (Gamma::incompleteGamma($degrees / 2, $value / 2) / Gamma::gammaValue($degrees / 2)); + } + + /** + * CHIINV. + * + * Returns the one-tailed probability of the chi-squared distribution. + * + * @param mixed (float) $probability Probability for the function + * @param mixed (int) $degrees degrees of freedom + * + * @return float|string + */ + public static function inverse($probability, $degrees) + { + $probability = Functions::flattenSingleValue($probability); + $degrees = Functions::flattenSingleValue($degrees); + + try { + $probability = self::validateFloat($probability); + $degrees = self::validateInt($degrees); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($probability < 0.0 || $probability > 1.0 || $degrees < 1) { + return Functions::NAN(); + } + + return self::calculateInverse($degrees, $probability); + } + + /** + * @return float|string + */ + protected static function calculateInverse(int $degrees, float $probability) + { + $xLo = 100; + $xHi = 0; + + $x = $xNew = 1; + $dx = 1; + $i = 0; + + while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { + // Apply Newton-Raphson step + $result = 1 - (Gamma::incompleteGamma($degrees / 2, $x / 2) + / Gamma::gammaValue($degrees / 2)); + $error = $result - $probability; + + if ($error == 0.0) { + $dx = 0; + } elseif ($error < 0.0) { + $xLo = $x; + } else { + $xHi = $x; + } + + // Avoid division by zero + if ($result != 0.0) { + $dx = $error / $result; + $xNew = $x - $dx; + } + + // If the NR fails to converge (which for example may be the + // case if the initial guess is too rough) we apply a bisection + // step to determine a more narrow interval around the root. + if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { + $xNew = ($xLo + $xHi) / 2; + $dx = $xNew - $x; + } + $x = $xNew; + } + + if ($i === self::MAX_ITERATIONS) { + return Functions::NA(); + } + + return $x; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php new file mode 100644 index 00000000..1d3a7be4 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php @@ -0,0 +1,63 @@ +getMessage(); + } + + if (($value <= -1) || ($value >= 1)) { + return Functions::NAN(); + } + + return 0.5 * log((1 + $value) / (1 - $value)); + } + + /** + * FISHERINV. + * + * Returns the inverse of the Fisher transformation. Use this transformation when + * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then + * FISHERINV(y) = x. + * + * @param mixed (float) $value + * + * @return float|string + */ + public static function inverse($value) + { + $value = Functions::flattenSingleValue($value); + + try { + self::validateFloat($value); + } catch (Exception $e) { + return $e->getMessage(); + } + + return (exp(2 * $value) - 1) / (exp(2 * $value) + 1); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php new file mode 100644 index 00000000..aa487329 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php @@ -0,0 +1,129 @@ +getMessage(); + } + + if ((((int) $value) == ((float) $value)) && $value <= 0.0) { + return Functions::NAN(); + } + + return self::gammaValue($value); + } + + /** + * GAMMADIST. + * + * Returns the gamma distribution. + * + * @param mixed (float) $value Value at which you want to evaluate the distribution + * @param mixed (float) $a Parameter to the distribution + * @param mixed (float) $b Parameter to the distribution + * @param mixed (bool) $cumulative + * + * @return float|string + */ + public static function distribution($value, $a, $b, $cumulative) + { + $value = Functions::flattenSingleValue($value); + $a = Functions::flattenSingleValue($a); + $b = Functions::flattenSingleValue($b); + + try { + $value = self::validateFloat($value); + $a = self::validateFloat($a); + $b = self::validateFloat($b); + $cumulative = self::validateBool($cumulative); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (($value < 0) || ($a <= 0) || ($b <= 0)) { + return Functions::NAN(); + } + + return self::calculateDistribution($value, $a, $b, $cumulative); + } + + /** + * GAMMAINV. + * + * Returns the inverse of the Gamma distribution. + * + * @param mixed (float) $probability Probability at which you want to evaluate the distribution + * @param mixed (float) $alpha Parameter to the distribution + * @param mixed (float) $beta Parameter to the distribution + * + * @return float|string + */ + public static function inverse($probability, $alpha, $beta) + { + $probability = Functions::flattenSingleValue($probability); + $alpha = Functions::flattenSingleValue($alpha); + $beta = Functions::flattenSingleValue($beta); + + try { + $probability = self::validateFloat($probability); + $alpha = self::validateFloat($alpha); + $beta = self::validateFloat($beta); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (($alpha <= 0.0) || ($beta <= 0.0) || ($probability < 0.0) || ($probability > 1.0)) { + return Functions::NAN(); + } + + return self::calculateInverse($probability, $alpha, $beta); + } + + /** + * GAMMALN. + * + * Returns the natural logarithm of the gamma function. + * + * @param mixed (float) $value + * + * @return float|string + */ + public static function ln($value) + { + $value = Functions::flattenSingleValue($value); + + try { + $value = self::validateFloat($value); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($value <= 0) { + return Functions::NAN(); + } + + return log(self::gammaValue($value)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php new file mode 100644 index 00000000..ae951af3 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php @@ -0,0 +1,377 @@ + Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { + // Apply Newton-Raphson step + $error = self::calculateDistribution($x, $alpha, $beta, true) - $probability; + if ($error < 0.0) { + $xLo = $x; + } else { + $xHi = $x; + } + + $pdf = self::calculateDistribution($x, $alpha, $beta, false); + // Avoid division by zero + if ($pdf !== 0.0) { + $dx = $error / $pdf; + $xNew = $x - $dx; + } + + // If the NR fails to converge (which for example may be the + // case if the initial guess is too rough) we apply a bisection + // step to determine a more narrow interval around the root. + if (($xNew < $xLo) || ($xNew > $xHi) || ($pdf == 0.0)) { + $xNew = ($xLo + $xHi) / 2; + $dx = $xNew - $x; + } + $x = $xNew; + } + + if ($i === self::MAX_ITERATIONS) { + return Functions::NA(); + } + + return $x; + } + + // + // Implementation of the incomplete Gamma function + // + public static function incompleteGamma(float $a, float $x): float + { + static $max = 32; + $summer = 0; + for ($n = 0; $n <= $max; ++$n) { + $divisor = $a; + for ($i = 1; $i <= $n; ++$i) { + $divisor *= ($a + $i); + } + $summer += ($x ** $n / $divisor); + } + + return $x ** $a * exp(0 - $x) * $summer; + } + + // + // Implementation of the Gamma function + // + public static function gammaValue(float $value): float + { + if ($value == 0.0) { + return 0; + } + + static $p0 = 1.000000000190015; + static $p = [ + 1 => 76.18009172947146, + 2 => -86.50532032941677, + 3 => 24.01409824083091, + 4 => -1.231739572450155, + 5 => 1.208650973866179e-3, + 6 => -5.395239384953e-6, + ]; + + $y = $x = $value; + $tmp = $x + 5.5; + $tmp -= ($x + 0.5) * log($tmp); + + $summer = $p0; + for ($j = 1; $j <= 6; ++$j) { + $summer += ($p[$j] / ++$y); + } + + return exp(0 - $tmp + log(self::SQRT2PI * $summer / $x)); + } + + /** + * logGamma function. + * + * @version 1.1 + * + * @author Jaco van Kooten + * + * Original author was Jaco van Kooten. Ported to PHP by Paul Meagher. + * + * The natural logarithm of the gamma function.
+ * Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz
+ * Applied Mathematics Division
+ * Argonne National Laboratory
+ * Argonne, IL 60439
+ *

+ * References: + *

    + *
  1. W. J. Cody and K. E. Hillstrom, 'Chebyshev Approximations for the Natural + * Logarithm of the Gamma Function,' Math. Comp. 21, 1967, pp. 198-203.
  2. + *
  3. K. E. Hillstrom, ANL/AMD Program ANLC366S, DGAMMA/DLGAMA, May, 1969.
  4. + *
  5. Hart, Et. Al., Computer Approximations, Wiley and sons, New York, 1968.
  6. + *
+ *

+ *

+ * From the original documentation: + *

+ *

+ * This routine calculates the LOG(GAMMA) function for a positive real argument X. + * Computation is based on an algorithm outlined in references 1 and 2. + * The program uses rational functions that theoretically approximate LOG(GAMMA) + * to at least 18 significant decimal digits. The approximation for X > 12 is from + * reference 3, while approximations for X < 12.0 are similar to those in reference + * 1, but are unpublished. The accuracy achieved depends on the arithmetic system, + * the compiler, the intrinsic functions, and proper selection of the + * machine-dependent constants. + *

+ *

+ * Error returns:
+ * The program returns the value XINF for X .LE. 0.0 or when overflow would occur. + * The computation is believed to be free of underflow and overflow. + *

+ * + * @return float MAX_VALUE for x < 0.0 or when overflow would occur, i.e. x > 2.55E305 + */ + + // Log Gamma related constants + private const LG_D1 = -0.5772156649015328605195174; + + private const LG_D2 = 0.4227843350984671393993777; + + private const LG_D4 = 1.791759469228055000094023; + + private const LG_P1 = [ + 4.945235359296727046734888, + 201.8112620856775083915565, + 2290.838373831346393026739, + 11319.67205903380828685045, + 28557.24635671635335736389, + 38484.96228443793359990269, + 26377.48787624195437963534, + 7225.813979700288197698961, + ]; + + private const LG_P2 = [ + 4.974607845568932035012064, + 542.4138599891070494101986, + 15506.93864978364947665077, + 184793.2904445632425417223, + 1088204.76946882876749847, + 3338152.967987029735917223, + 5106661.678927352456275255, + 3074109.054850539556250927, + ]; + + private const LG_P4 = [ + 14745.02166059939948905062, + 2426813.369486704502836312, + 121475557.4045093227939592, + 2663432449.630976949898078, + 29403789566.34553899906876, + 170266573776.5398868392998, + 492612579337.743088758812, + 560625185622.3951465078242, + ]; + + private const LG_Q1 = [ + 67.48212550303777196073036, + 1113.332393857199323513008, + 7738.757056935398733233834, + 27639.87074403340708898585, + 54993.10206226157329794414, + 61611.22180066002127833352, + 36351.27591501940507276287, + 8785.536302431013170870835, + ]; + + private const LG_Q2 = [ + 183.0328399370592604055942, + 7765.049321445005871323047, + 133190.3827966074194402448, + 1136705.821321969608938755, + 5267964.117437946917577538, + 13467014.54311101692290052, + 17827365.30353274213975932, + 9533095.591844353613395747, + ]; + + private const LG_Q4 = [ + 2690.530175870899333379843, + 639388.5654300092398984238, + 41355999.30241388052042842, + 1120872109.61614794137657, + 14886137286.78813811542398, + 101680358627.2438228077304, + 341747634550.7377132798597, + 446315818741.9713286462081, + ]; + + private const LG_C = [ + -0.001910444077728, + 8.4171387781295e-4, + -5.952379913043012e-4, + 7.93650793500350248e-4, + -0.002777777777777681622553, + 0.08333333333333333331554247, + 0.0057083835261, + ]; + + // Rough estimate of the fourth root of logGamma_xBig + private const LG_FRTBIG = 2.25e76; + + private const PNT68 = 0.6796875; + + // Function cache for logGamma + private static $logGammaCacheResult = 0.0; + + private static $logGammaCacheX = 0.0; + + public static function logGamma(float $x): float + { + if ($x == self::$logGammaCacheX) { + return self::$logGammaCacheResult; + } + + $y = $x; + if ($y > 0.0 && $y <= self::LOG_GAMMA_X_MAX_VALUE) { + if ($y <= self::EPS) { + $res = -log($y); + } elseif ($y <= 1.5) { + $res = self::logGamma1($y); + } elseif ($y <= 4.0) { + $res = self::logGamma2($y); + } elseif ($y <= 12.0) { + $res = self::logGamma3($y); + } else { + $res = self::logGamma4($y); + } + } else { + // -------------------------- + // Return for bad arguments + // -------------------------- + $res = self::MAX_VALUE; + } + + // ------------------------------ + // Final adjustments and return + // ------------------------------ + self::$logGammaCacheX = $x; + self::$logGammaCacheResult = $res; + + return $res; + } + + private static function logGamma1(float $y) + { + // --------------------- + // EPS .LT. X .LE. 1.5 + // --------------------- + if ($y < self::PNT68) { + $corr = -log($y); + $xm1 = $y; + } else { + $corr = 0.0; + $xm1 = $y - 1.0; + } + + $xden = 1.0; + $xnum = 0.0; + if ($y <= 0.5 || $y >= self::PNT68) { + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm1 + self::LG_P1[$i]; + $xden = $xden * $xm1 + self::LG_Q1[$i]; + } + + return $corr + $xm1 * (self::LG_D1 + $xm1 * ($xnum / $xden)); + } + + $xm2 = $y - 1.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm2 + self::LG_P2[$i]; + $xden = $xden * $xm2 + self::LG_Q2[$i]; + } + + return $corr + $xm2 * (self::LG_D2 + $xm2 * ($xnum / $xden)); + } + + private static function logGamma2(float $y) + { + // --------------------- + // 1.5 .LT. X .LE. 4.0 + // --------------------- + $xm2 = $y - 2.0; + $xden = 1.0; + $xnum = 0.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm2 + self::LG_P2[$i]; + $xden = $xden * $xm2 + self::LG_Q2[$i]; + } + + return $xm2 * (self::LG_D2 + $xm2 * ($xnum / $xden)); + } + + protected static function logGamma3(float $y) + { + // ---------------------- + // 4.0 .LT. X .LE. 12.0 + // ---------------------- + $xm4 = $y - 4.0; + $xden = -1.0; + $xnum = 0.0; + for ($i = 0; $i < 8; ++$i) { + $xnum = $xnum * $xm4 + self::LG_P4[$i]; + $xden = $xden * $xm4 + self::LG_Q4[$i]; + } + + return self::LG_D4 + $xm4 * ($xnum / $xden); + } + + protected static function logGamma4(float $y) + { + // --------------------------------- + // Evaluate for argument .GE. 12.0 + // --------------------------------- + $res = 0.0; + if ($y <= self::LG_FRTBIG) { + $res = self::LG_C[6]; + $ysq = $y * $y; + for ($i = 0; $i < 6; ++$i) { + $res = $res / $ysq + self::LG_C[$i]; + } + $res /= $y; + $corr = log($y); + $res = $res + log(self::SQRT2PI) - 0.5 * $corr; + $res += $y * ($corr - 1.0); + } + + return $res; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php index 84c10719..5d03e5d5 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -16,8 +16,8 @@ class Permutations * combinations, for which the internal order is not significant. Use this function * for lottery-style probability calculations. * - * @param int $numObjs Number of different objects - * @param int $numInSet Number of objects in each permutation + * @param mixed (int) $numObjs Number of different objects + * @param mixed (int) $numInSet Number of objects in each permutation * * @return int|string Number of permutations, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php b/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php index 28a25a75..4f15615c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php @@ -23,7 +23,7 @@ class StandardDeviations extends VarianceBase { $aArgs = Functions::flattenArrayIndexed($args); - $aMean = Averages::AVERAGE($aArgs); + $aMean = Averages::average($aArgs); if (!is_string($aMean)) { $returnValue = 0.0; @@ -67,7 +67,7 @@ class StandardDeviations extends VarianceBase { $aArgs = Functions::flattenArrayIndexed($args); - $aMean = Averages::AVERAGEA($aArgs); + $aMean = Averages::averageA($aArgs); if (!is_string($aMean)) { $returnValue = 0.0; @@ -109,7 +109,7 @@ class StandardDeviations extends VarianceBase { $aArgs = Functions::flattenArrayIndexed($args); - $aMean = Averages::AVERAGE($aArgs); + $aMean = Averages::average($aArgs); if (!is_string($aMean)) { $returnValue = 0.0; @@ -153,7 +153,7 @@ class StandardDeviations extends VarianceBase { $aArgs = Functions::flattenArrayIndexed($args); - $aMean = Averages::AVERAGEA($aArgs); + $aMean = Averages::averageA($aArgs); if (!is_string($aMean)) { $returnValue = 0.0; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index a1137cef..b1dfbaef 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -107,7 +107,7 @@ class Trends * Calculates, or predicts, a future value by using existing values. * The predicted value is a y-value for a given x-value. * - * @param float $xValue Value of X for which we want to find Y + * @param mixed (float) $xValue Value of X for which we want to find Y * @param mixed $yValues array of mixed Data Series Y * @param mixed $xValues of mixed Data Series X * @@ -140,7 +140,7 @@ class Trends * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @param mixed[] $newValues Values of X for which we want to find Y - * @param bool $const a logical value specifying whether to force the intersect to equal 0 + * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 * * @return array of float */ @@ -196,8 +196,8 @@ class Trends * * @param mixed[] $yValues Data Series Y * @param null|mixed[] $xValues Data Series X - * @param bool $const a logical value specifying whether to force the intersect to equal 0 - * @param bool $stats a logical value specifying whether to return additional regression statistics + * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 + * @param mixed (bool) $stats a logical value specifying whether to return additional regression statistics * * @return array|int|string The result, or a string containing an error */ @@ -257,8 +257,8 @@ class Trends * * @param mixed[] $yValues Data Series Y * @param null|mixed[] $xValues Data Series X - * @param bool $const a logical value specifying whether to force the intersect to equal 0 - * @param bool $stats a logical value specifying whether to return additional regression statistics + * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 + * @param mixed (bool) $stats a logical value specifying whether to return additional regression statistics * * @return array|int|string The result, or a string containing an error */ @@ -397,7 +397,7 @@ class Trends * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @param mixed[] $newValues Values of X for which we want to find Y - * @param bool $const a logical value specifying whether to force the intersect to equal 0 + * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 * * @return array of float */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php index 2a275133..846a3124 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php +++ b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php @@ -13,7 +13,7 @@ class CaseConvert * * Converts a string value to upper case. * - * @param string $mixedCaseValue + * @param mixed (string) $mixedCaseValue */ public static function lower($mixedCaseValue): string { @@ -31,7 +31,7 @@ class CaseConvert * * Converts a string value to upper case. * - * @param string $mixedCaseValue + * @param mixed (string) $mixedCaseValue */ public static function upper($mixedCaseValue): string { @@ -49,7 +49,7 @@ class CaseConvert * * Converts a string value to upper case. * - * @param string $mixedCaseValue + * @param mixed (string) $mixedCaseValue */ public static function proper($mixedCaseValue): string { diff --git a/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php index 2263b1a7..0003e0cd 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php +++ b/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php @@ -10,7 +10,7 @@ class CharacterConvert /** * CHARACTER. * - * @param string $character Value + * @param mixed (int) $character Value */ public static function character($character): string { @@ -31,7 +31,7 @@ class CharacterConvert /** * ASCIICODE. * - * @param string $characters Value + * @param mixed (string) $characters Value * * @return int|string A string if arguments are invalid */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/Extract.php b/src/PhpSpreadsheet/Calculation/TextData/Extract.php index 126d9f49..7ef76546 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Extract.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Extract.php @@ -10,8 +10,8 @@ class Extract /** * LEFT. * - * @param string $value Value - * @param int $chars Number of characters + * @param mixed (string) $value Value + * @param mixed (int) $chars Number of characters */ public static function left($value = '', $chars = 1): string { @@ -32,9 +32,9 @@ class Extract /** * MID. * - * @param string $value Value - * @param int $start Start character - * @param int $chars Number of characters + * @param mixed (string) $value Value + * @param mixed (int) $start Start character + * @param mixed (int) $chars Number of characters */ public static function mid($value = '', $start = 1, $chars = null): string { @@ -56,8 +56,8 @@ class Extract /** * RIGHT. * - * @param string $value Value - * @param int $chars Number of characters + * @param mixed (string) $value Value + * @param mixed (int) $chars Number of characters */ public static function right($value = '', $chars = 1): string { diff --git a/src/PhpSpreadsheet/Calculation/TextData/Format.php b/src/PhpSpreadsheet/Calculation/TextData/Format.php index 2cea474d..f24ed7ae 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Format.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -18,8 +18,8 @@ class Format * This function converts a number to text using currency format, with the decimals rounded to the specified place. * The format used is $#,##0.00_);($#,##0.00).. * - * @param float $value The value to format - * @param int $decimals The number of digits to display to the right of the decimal point. + * @param mixed (float) $value The value to format + * @param mixed (int) $decimals The number of digits to display to the right of the decimal point. * If decimals is negative, number is rounded to the left of the decimal point. * If you omit decimals, it is assumed to be 2 */ @@ -54,7 +54,7 @@ class Format * * @param mixed $value Value to check * @param mixed $decimals - * @param bool $noCommas + * @param mixed (bool) $noCommas */ public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false): string { @@ -72,7 +72,7 @@ class Format if ($decimals < 0) { $decimals = 0; } - if (!$noCommas) { + if ($noCommas === false) { $valueResult = number_format( $valueResult, $decimals, @@ -88,7 +88,7 @@ class Format * TEXTFORMAT. * * @param mixed $value Value to check - * @param string $format Format mask to use + * @param mixed (string) $format Format mask to use */ public static function TEXTFORMAT($value, $format): string { @@ -152,8 +152,8 @@ class Format * NUMBERVALUE. * * @param mixed $value Value to check - * @param string $decimalSeparator decimal separator, defaults to locale defined value - * @param string $groupSeparator group/thosands separator, defaults to locale defined value + * @param mixed (string) $decimalSeparator decimal separator, defaults to locale defined value + * @param mixed (string) $groupSeparator group/thosands separator, defaults to locale defined value * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/Replace.php b/src/PhpSpreadsheet/Calculation/TextData/Replace.php index 9a849ba0..a06d4364 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Replace.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Replace.php @@ -10,10 +10,10 @@ class Replace /** * REPLACE. * - * @param string $oldText String to modify - * @param int $start Start character - * @param int $chars Number of characters - * @param string $newText String to replace in defined position + * @param mixed (string) $oldText String to modify + * @param mixed (int) $start Start character + * @param mixed (int) $chars Number of characters + * @param mixed (string) $newText String to replace in defined position */ public static function replace($oldText, $start, $chars, $newText): string { @@ -31,10 +31,10 @@ class Replace /** * SUBSTITUTE. * - * @param string $text Value - * @param string $fromText From Value - * @param string $toText To Value - * @param int $instance Instance Number + * @param mixed (string) $text Value + * @param mixed (string) $fromText From Value + * @param mixed (string) $toText To Value + * @param mixed (int) $instance Instance Number */ public static function substitute($text = '', $fromText = '', $toText = '', $instance = 0): string { diff --git a/src/PhpSpreadsheet/Calculation/TextData/Search.php b/src/PhpSpreadsheet/Calculation/TextData/Search.php index acbe6a24..cf1bf241 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Search.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Search.php @@ -11,9 +11,9 @@ class Search /** * SEARCHSENSITIVE. * - * @param string $needle The string to look for - * @param string $haystack The string in which to look - * @param int $offset Offset within $haystack + * @param mixed (string) $needle The string to look for + * @param mixed (string) $haystack The string in which to look + * @param mixed (int) $offset Offset within $haystack * * @return int|string */ @@ -46,9 +46,9 @@ class Search /** * SEARCHINSENSITIVE. * - * @param string $needle The string to look for - * @param string $haystack The string in which to look - * @param int $offset Offset within $haystack + * @param mixed (string) $needle The string to look for + * @param mixed (string) $haystack The string in which to look + * @param mixed (int) $offset Offset within $haystack * * @return int|string */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/Text.php b/src/PhpSpreadsheet/Calculation/TextData/Text.php index a47d373b..338cdd20 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Text.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Text.php @@ -10,7 +10,7 @@ class Text /** * STRINGLENGTH. * - * @param string $value Value + * @param mixed (string) $value Value */ public static function length($value = ''): int { @@ -28,8 +28,8 @@ class Text * EXACT is case-sensitive but ignores formatting differences. * Use EXACT to test text being entered into a document. * - * @param $value1 - * @param $value2 + * @param mixed (string) $value1 + * @param mixed (string) $value2 */ public static function exact($value1, $value2): bool { diff --git a/src/PhpSpreadsheet/Calculation/TextData/Trim.php b/src/PhpSpreadsheet/Calculation/TextData/Trim.php index 0d5688b0..01fff1a8 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Trim.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Trim.php @@ -12,7 +12,7 @@ class Trim /** * TRIMNONPRINTABLE. * - * @param mixed $stringValue Value to check + * @param mixed (string) $stringValue Value to check * * @return null|string */ @@ -38,7 +38,7 @@ class Trim /** * TRIMSPACES. * - * @param mixed $stringValue Value to check + * @param mixed (string) $stringValue Value to check * * @return null|string */ diff --git a/tests/data/Calculation/Statistical/BETADIST.php b/tests/data/Calculation/Statistical/BETADIST.php index 9fbecaaa..2046e189 100644 --- a/tests/data/Calculation/Statistical/BETADIST.php +++ b/tests/data/Calculation/Statistical/BETADIST.php @@ -25,12 +25,56 @@ return [ 0.685470581054, 2, 8, 10, 1, 3, ], + [ + 0.4059136, + 0.4, 4, 5, + ], + [ + '#VALUE!', + 'NAN', 8, 10, 1, 3, + ], [ '#VALUE!', 2, 'NAN', 10, 1, 3, ], [ + '#VALUE!', + 2, 8, 'NAN', 1, 3, + ], + [ + '#VALUE!', + 2, 8, 10, 'NAN', 3, + ], + [ + '#VALUE!', + 2, 8, 10, 1, 'NAN', + ], + 'alpha < 0' => [ '#NUM!', 2, -8, 10, 1, 3, ], + 'alpha = 0' => [ + '#NUM!', + 2, 0, 10, 1, 3, + ], + 'beta < 0' => [ + '#NUM!', + 2, 8, -10, 1, 3, + ], + 'beta = 0' => [ + '#NUM!', + 2, 8, 0, 1, 3, + ], + 'value < Min' => [ + '#NUM!', + 0.5, 8, 10, 1, 3, + ], + 'value > Max' => [ + '#NUM!', + 3.5, 8, 10, 1, 3, + ], + 'Min = Max' => [ + '#NUM!', + 2, 8, 10, 2, 2, + ], ]; diff --git a/tests/data/Calculation/Statistical/BETAINV.php b/tests/data/Calculation/Statistical/BETAINV.php index 5afe14cb..4d8cb5bd 100644 --- a/tests/data/Calculation/Statistical/BETAINV.php +++ b/tests/data/Calculation/Statistical/BETAINV.php @@ -25,12 +25,56 @@ return [ 0.303225844664, 0.2, 4, 5, 0, 1, ], + [ + '#VALUE!', + 'NAN', 4, 5, 0, 1, + ], [ '#VALUE!', 0.2, 'NAN', 5, 0, 1, ], [ + '#VALUE!', + 0.2, 4, 'NAN', 0, 1, + ], + [ + '#VALUE!', + 0.2, 4, 5, 'NAN', 1, + ], + [ + '#VALUE!', + 0.2, 4, 5, 0, 'NAN', + ], + 'alpha < 0' => [ '#NUM!', 0.2, -4, 5, 0, 1, ], + 'alpha = 0' => [ + '#NUM!', + 0.2, 0, 5, 0, 1, + ], + 'beta < 0' => [ + '#NUM!', + 0.2, 4, -5, 0, 1, + ], + 'beta = 0' => [ + '#NUM!', + 0.2, 4, 0, 0, 1, + ], + 'Probability < 0' => [ + '#NUM!', + -0.5, 4, 5, 1, 3, + ], + 'Probability = 0' => [ + '#NUM!', + 0.0, 4, 5, 1, 3, + ], + 'Probability > 1' => [ + '#NUM!', + 1.5, 4, 5, 1, 3, + ], + 'Min = Max' => [ + '#NUM!', + 1, 4, 5, 1, 1, + ], ]; diff --git a/tests/data/Calculation/Statistical/CHIDIST.php b/tests/data/Calculation/Statistical/CHIDIST.php index 5cfdc664..24ddab9f 100644 --- a/tests/data/Calculation/Statistical/CHIDIST.php +++ b/tests/data/Calculation/Statistical/CHIDIST.php @@ -35,14 +35,18 @@ return [ ], [ '#VALUE!', - 'NAN', 3, + 'NaN', 3, ], [ - '#NUM!', - 8, 0, + '#VALUE!', + 8, 'NaN', ], - [ + 'Value < 0' => [ '#NUM!', -8, 3, ], + 'Degrees < 1' => [ + '#NUM!', + 8, 0, + ], ]; diff --git a/tests/data/Calculation/Statistical/CHIINV.php b/tests/data/Calculation/Statistical/CHIINV.php index 2384cda6..f931a780 100644 --- a/tests/data/Calculation/Statistical/CHIINV.php +++ b/tests/data/Calculation/Statistical/CHIINV.php @@ -35,6 +35,22 @@ return [ ], [ '#VALUE!', - 0.25, 'NAN', + 'NaN', 3, + ], + [ + '#VALUE!', + 0.25, 'NaN', + ], + 'Probability < 0' => [ + '#NUM!', + -0.1, 3, + ], + 'Probability > 1' => [ + '#NUM!', + 1.1, 3, + ], + 'Freedom > 1' => [ + '#NUM!', + 0.1, 0.5, ], ]; diff --git a/tests/data/Calculation/Statistical/FISHER.php b/tests/data/Calculation/Statistical/FISHER.php index 12909012..faf6442e 100644 --- a/tests/data/Calculation/Statistical/FISHER.php +++ b/tests/data/Calculation/Statistical/FISHER.php @@ -13,12 +13,20 @@ return [ 1.098612288668, 0.8, ], + [ + 0.972955074528, + 0.75, + ], [ '#VALUE!', 'NAN', ], [ '#NUM!', - -2, + -1.5, + ], + [ + '#NUM!', + 1.5, ], ]; diff --git a/tests/data/Calculation/Statistical/FISHERINV.php b/tests/data/Calculation/Statistical/FISHERINV.php index b79fd4f8..d23472b2 100644 --- a/tests/data/Calculation/Statistical/FISHERINV.php +++ b/tests/data/Calculation/Statistical/FISHERINV.php @@ -17,6 +17,10 @@ return [ 0.992631520201, 2.8, ], + [ + 0.7499999990254, + 0.9729550723, + ], [ '#VALUE!', 'NAN', diff --git a/tests/data/Calculation/Statistical/GAMMA.php b/tests/data/Calculation/Statistical/GAMMA.php index 760b429d..24b83f04 100644 --- a/tests/data/Calculation/Statistical/GAMMA.php +++ b/tests/data/Calculation/Statistical/GAMMA.php @@ -6,8 +6,10 @@ return [ [9.513507698669, 0.1], [1.0, 1.0], [0.886226925453, 1.5], + [1.3293403881791, 2.5], [17.837861981813, 4.8], [52.342777784553, 5.5], - ['#NUM!', -1], + 'Zero value' => ['#NUM!', 0.0], + 'Negative integer value' => ['#NUM!', -1], ['#VALUE!', 'NAN'], ]; diff --git a/tests/data/Calculation/Statistical/GAMMADIST.php b/tests/data/Calculation/Statistical/GAMMADIST.php index e79b3869..2a1bfa14 100644 --- a/tests/data/Calculation/Statistical/GAMMADIST.php +++ b/tests/data/Calculation/Statistical/GAMMADIST.php @@ -17,12 +17,44 @@ return [ 0.576809918873, 6, 3, 2, true, ], + 'Boolean as numeric' => [ + 0.576809918873, + 6, 3, 2, 1, + ], + [ + '#VALUE!', + 'NAN', 3, 2, true, + ], [ '#VALUE!', 6, 'NAN', 2, true, ], [ + '#VALUE!', + 6, 3, 'NAN', true, + ], + [ + '#VALUE!', + 6, 3, 2, 'NAN', + ], + 'Value < 0' => [ '#NUM!', -6, 3, 2, true, ], + 'A < 0' => [ + '#NUM!', + 6, -3, 2, true, + ], + 'A = 0' => [ + '#NUM!', + 6, 0, 2, true, + ], + 'B < 0' => [ + '#NUM!', + 6, 3, -2, true, + ], + 'B = 0' => [ + '#NUM!', + 6, 3, 0, true, + ], ]; diff --git a/tests/data/Calculation/Statistical/GAMMAINV.php b/tests/data/Calculation/Statistical/GAMMAINV.php index 3b3604b4..c35c4219 100644 --- a/tests/data/Calculation/Statistical/GAMMAINV.php +++ b/tests/data/Calculation/Statistical/GAMMAINV.php @@ -11,10 +11,38 @@ return [ ], [ '#VALUE!', - 'NAN', 3, 2, + 'NaN', 3, 2, ], [ + '#VALUE!', + 0.5, 'NaN', 2, + ], + [ + '#VALUE!', + 0.5, 3, 'NaN', + ], + 'Probability < 0' => [ '#NUM!', -0.5, 3, 2, ], + 'Probability > 1' => [ + '#NUM!', + 1.5, 3, 2, + ], + 'Alpha < 0' => [ + '#NUM!', + 0.5, -3, 2, + ], + 'Alpha = 0' => [ + '#NUM!', + 0.5, 0, 2, + ], + 'Beta < 0' => [ + '#NUM!', + 0.5, 3, -2, + ], + 'Beta = 0' => [ + '#NUM!', + 0.5, 3, 0, + ], ]; diff --git a/tests/data/Calculation/Statistical/GAMMALN.php b/tests/data/Calculation/Statistical/GAMMALN.php index a415f559..7b43eea8 100644 --- a/tests/data/Calculation/Statistical/GAMMALN.php +++ b/tests/data/Calculation/Statistical/GAMMALN.php @@ -13,8 +13,12 @@ return [ '#VALUE!', 'NAN', ], - [ + 'Value < 0' => [ '#NUM!', -4.5, ], + 'Value = 0' => [ + '#NUM!', + 0.0, + ], ]; diff --git a/tests/data/Calculation/TextData/FIND.php b/tests/data/Calculation/TextData/FIND.php index 0a583456..04d3276d 100644 --- a/tests/data/Calculation/TextData/FIND.php +++ b/tests/data/Calculation/TextData/FIND.php @@ -101,4 +101,9 @@ return [ 'Mark Baker', 8, ], + 'Boolean Needle' => [ + '#VALUE!', + true, + 'Mark Baker', + ], ]; diff --git a/tests/data/Calculation/TextData/SEARCH.php b/tests/data/Calculation/TextData/SEARCH.php index 579830f6..fa970bec 100644 --- a/tests/data/Calculation/TextData/SEARCH.php +++ b/tests/data/Calculation/TextData/SEARCH.php @@ -94,4 +94,9 @@ return [ 'BITE', 'BIT', ], + 'Boolean Needle' => [ + '#VALUE!', + true, + 'Mark Baker', + ], ]; From c380b25d3cf7843765462cdac3ae163b34a935a8 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 26 Mar 2021 09:08:23 +0100 Subject: [PATCH 134/187] Extract Poisson distribution into its own class (#1953) --- .../Calculation/Calculation.php | 4 +- .../Calculation/DateTimeExcel/Days360.php | 2 +- .../Calculation/Engineering/Complex.php | 6 +- src/PhpSpreadsheet/Calculation/Financial.php | 42 +++++----- .../Calculation/Financial/Depreciation.php | 14 ++-- src/PhpSpreadsheet/Calculation/Functions.php | 4 +- src/PhpSpreadsheet/Calculation/LookupRef.php | 4 +- .../Calculation/LookupRef/Matrix.php | 2 +- .../Calculation/Statistical.php | 77 ++++++++----------- .../Statistical/Distributions/Poisson.php | 55 +++++++++++++ .../data/Calculation/Statistical/POISSON.php | 16 +++- 11 files changed, 138 insertions(+), 88 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 80a6fbcc..792402ce 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1963,12 +1963,12 @@ class Calculation ], 'POISSON' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'POISSON'], + 'functionCall' => [Statistical\Distributions\Poisson::class, 'distribution'], 'argumentCount' => '3', ], 'POISSON.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'POISSON'], + 'functionCall' => [Statistical\Distributions\Poisson::class, 'distribution'], 'argumentCount' => '3', ], 'POWER' => [ diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php index 068ea2bc..b90bc367 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php @@ -22,7 +22,7 @@ class Days360 * PHP DateTime object, or a standard date string * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string - * @param bool $method US or European Method + * @param mixed (bool) $method US or European Method * FALSE or omitted: U.S. (NASD) method. If the starting date is * the last day of a month, it becomes equal to the 30th of the * same month. If the ending date is the last day of a month and diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php index f6429cbd..7dd5ff95 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php @@ -16,9 +16,9 @@ class Complex * Excel Function: * COMPLEX(realNumber,imaginary[,suffix]) * - * @param float $realNumber the real coefficient of the complex number - * @param float $imaginary the imaginary coefficient of the complex number - * @param string $suffix The suffix for the imaginary component of the complex number. + * @param mixed (float) $realNumber the real coefficient of the complex number + * @param mixed (float) $imaginary the imaginary coefficient of the complex number + * @param mixed (string) $suffix The suffix for the imaginary component of the complex number. * If omitted, the suffix is assumed to be "i". * * @return string diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 2b54e1cd..084562f8 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -42,15 +42,15 @@ class Financial * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date * when the security is traded to the buyer. - * @param float $rate the security's annual coupon rate - * @param float $par The security's par value. + * @param mixed (float) $rate the security's annual coupon rate + * @param mixed (float) $par The security's par value. * If you omit par, ACCRINT uses $1,000. - * @param int $frequency the number of coupon payments per year. + * @param mixed (int) $frequency the number of coupon payments per year. * Valid frequency values are: * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -98,10 +98,10 @@ class Financial * * @param mixed $issue The security's issue date * @param mixed $settlement The security's settlement (or maturity) date - * @param float $rate The security's annual coupon rate - * @param float $par The security's par value. + * @param mixed (float) $rate The security's annual coupon rate + * @param mixed (float) $par The security's par value. * If you omit par, ACCRINT uses $1,000. - * @param int $basis The type of day count to use. + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -890,11 +890,11 @@ class Financial * Excel Function: * IRR(values[,guess]) * - * @param float[] $values An array or a reference to cells that contain numbers for which you want + * @param mixed (float[]) $values An array or a reference to cells that contain numbers for which you want * to calculate the internal rate of return. * Values must contain at least one positive value and one negative value to * calculate the internal rate of return. - * @param float $guess A number that you guess is close to the result of IRR + * @param mixed (float) $guess A number that you guess is close to the result of IRR * * @return float|string */ @@ -1000,11 +1000,11 @@ class Financial * Excel Function: * MIRR(values,finance_rate, reinvestment_rate) * - * @param float[] $values An array or a reference to cells that contain a series of payments and + * @param mixed (float[]) $values An array or a reference to cells that contain a series of payments and * income occurring at regular intervals. * Payments are negative value, income is positive values. - * @param float $finance_rate The interest rate you pay on the money used in the cash flows - * @param float $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them + * @param mixed (float) $finance_rate The interest rate you pay on the money used in the cash flows + * @param mixed (float) $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them * * @return float|string Result, or a string containing an error */ @@ -1371,20 +1371,20 @@ class Financial * Excel Function: * RATE(nper,pmt,pv[,fv[,type[,guess]]]) * - * @param float $nper The total number of payment periods in an annuity - * @param float $pmt The payment made each period and cannot change over the life + * @param mixed (float) $nper The total number of payment periods in an annuity + * @param mixed (float) $pmt The payment made each period and cannot change over the life * of the annuity. * Typically, pmt includes principal and interest but no other * fees or taxes. - * @param float $pv The present value - the total amount that a series of future + * @param mixed (float) $pv The present value - the total amount that a series of future * payments is worth now - * @param float $fv The future value, or a cash balance you want to attain after + * @param mixed (float) $fv The future value, or a cash balance you want to attain after * the last payment is made. If fv is omitted, it is assumed * to be 0 (the future value of a loan, for example, is 0). - * @param int $type A number 0 or 1 and indicates when payments are due: + * @param mixed (int) $type A number 0 or 1 and indicates when payments are due: * 0 or omitted At the end of the period. * 1 At the beginning of the period. - * @param float $guess Your guess for what the rate will be. + * @param mixed (float) $guess Your guess for what the rate will be. * If you omit guess, it is assumed to be 10 percent. * * @return float|string @@ -1443,9 +1443,9 @@ class Financial * The security settlement date is the date after the issue 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 $investment The amount invested in the security - * @param int $discount The security's discount rate - * @param int $basis The type of day count to use. + * @param mixed (int) $investment The amount invested in the security + * @param mixed (int) $discount The security's discount rate + * @param mixed (int) $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 diff --git a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php index 173e29bb..8770242f 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php @@ -137,9 +137,9 @@ class Depreciation * * Returns the straight-line depreciation of an asset for one period * - * @param mixed $cost Initial cost of the asset - * @param mixed $salvage Value at the end of the depreciation - * @param mixed $life Number of periods over which the asset is depreciated + * @param mixed (float) $cost Initial cost of the asset + * @param mixed (float) $salvage Value at the end of the depreciation + * @param mixed (float) $life Number of periods over which the asset is depreciated * * @return float|string Result, or a string containing an error */ @@ -169,10 +169,10 @@ class Depreciation * * Returns the sum-of-years' digits depreciation of an asset for a specified period. * - * @param mixed $cost Initial cost of the asset - * @param mixed $salvage Value at the end of the depreciation - * @param mixed $life Number of periods over which the asset is depreciated - * @param mixed $period Period + * @param mixed (float) $cost Initial cost of the asset + * @param mixed (float) $salvage Value at the end of the depreciation + * @param mixed (float) $life Number of periods over which the asset is depreciated + * @param mixed (float) $period Period * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index 022e6be5..6ad387e8 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -576,7 +576,7 @@ class Functions /** * Convert a multi-dimensional array to a simple 1-dimensional array. * - * @param array $array Array to be flattened + * @param mixed (array) $array Array to be flattened * * @return array Flattened array */ @@ -609,7 +609,7 @@ class Functions /** * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing. * - * @param array $array Array to be flattened + * @param mixed (array) $array Array to be flattened * * @return array Flattened array */ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index 17115a06..4a1bcb06 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -148,8 +148,8 @@ class LookupRef * Excel Function: * =HYPERLINK(linkURL,displayName) * - * @param string $linkURL Value to check, is also the value returned when no error - * @param string $displayName Value to return when testValue is an error condition + * @param mixed (string) $linkURL Value to check, is also the value returned when no error + * @param mixed (string) $displayName Value to return when testValue is an error condition * @param Cell $pCell The cell to set the hyperlink in * * @return mixed The value of $displayName (or $linkURL if $displayName was blank) diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php index 8859a287..59af4258 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php @@ -9,7 +9,7 @@ class Matrix /** * TRANSPOSE. * - * @param array $matrixData A matrix of values + * @param mixed (array) $matrixData A matrix of values * * @return array */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index c8e084b5..ca160c36 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -251,10 +251,10 @@ class Statistical * experiment. For example, BINOMDIST can calculate the probability that two of the next three * babies born are male. * - * @param float $value Number of successes in trials - * @param float $trials Number of trials - * @param float $probability Probability of success on each trial - * @param bool $cumulative + * @param mixed (float) $value Number of successes in trials + * @param mixed (float) $trials Number of trials + * @param mixed (float) $probability Probability of success on each trial + * @param mixed (bool) $cumulative * * @return float|string */ @@ -1502,9 +1502,9 @@ class Statistical * distribution, except that the number of successes is fixed, and the number of trials is * variable. Like the binomial, trials are assumed to be independent. * - * @param float $failures Number of Failures - * @param float $successes Threshold number of Successes - * @param float $probability Probability of success on each trial + * @param mixed (float) $failures Number of Failures + * @param mixed (float) $successes Threshold number of Successes + * @param mixed (float) $probability Probability of success on each trial * * @return float|string The result, or a string containing an error */ @@ -1539,10 +1539,10 @@ class Statistical * function has a very wide range of applications in statistics, including hypothesis * testing. * - * @param float $value - * @param float $mean Mean Value - * @param float $stdDev Standard Deviation - * @param bool $cumulative + * @param mixed (float) $value + * @param mixed (float) $mean Mean Value + * @param mixed (float) $stdDev Standard Deviation + * @param mixed (bool) $cumulative * * @return float|string The result, or a string containing an error */ @@ -1573,9 +1573,9 @@ class Statistical * * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. * - * @param float $probability - * @param float $mean Mean Value - * @param float $stdDev Standard Deviation + * @param mixed (float) $probability + * @param mixed (float) $mean Mean Value + * @param mixed (float) $stdDev Standard Deviation * * @return float|string The result, or a string containing an error */ @@ -1606,7 +1606,7 @@ class Statistical * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a * table of standard normal curve areas. * - * @param float $value + * @param mixed (float) $value * * @return float|string The result, or a string containing an error */ @@ -1627,8 +1627,8 @@ class Statistical * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a * table of standard normal curve areas. * - * @param float $value - * @param bool $cumulative + * @param mixed (float) $value + * @param mixed (bool) $cumulative * * @return float|string The result, or a string containing an error */ @@ -1648,7 +1648,7 @@ class Statistical * * Returns the inverse of the standard normal cumulative distribution * - * @param float $value + * @param mixed (float) $value * * @return float|string The result, or a string containing an error */ @@ -1714,9 +1714,9 @@ class Statistical * rather than floored (as MS Excel), so value 3 for a value set of 1, 2, 3, 4 will return * 0.667 rather than 0.666 * - * @param float[] $valueSet An array of, or a reference to, a list of numbers - * @param int $value the number whose rank you want to find - * @param int $significance the number of significant digits for the returned percentage value + * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers + * @param mixed (int) $value the number whose rank you want to find + * @param mixed (int) $significance the number of significant digits for the returned percentage value * * @return float|string (string if result is an error) */ @@ -1787,37 +1787,20 @@ class Statistical * is predicting the number of events over a specific time, such as the number of * cars arriving at a toll plaza in 1 minute. * - * @param float $value - * @param float $mean Mean Value - * @param bool $cumulative + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Poisson::distribution() + * Use the distribution() method in the Statistical\Distributions\Poisson class instead + * + * @param mixed (float) $value + * @param mixed (float) $mean Mean Value + * @param mixed (bool) $cumulative * * @return float|string The result, or a string containing an error */ public static function POISSON($value, $mean, $cumulative) { - $value = Functions::flattenSingleValue($value); - $mean = Functions::flattenSingleValue($mean); - - if ((is_numeric($value)) && (is_numeric($mean))) { - if (($value < 0) || ($mean <= 0)) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - $summer = 0; - $floor = floor($value); - for ($i = 0; $i <= $floor; ++$i) { - $summer += $mean ** $i / MathTrig::FACT($i); - } - - return exp(0 - $mean) * $summer; - } - - return (exp(0 - $mean) * $mean ** $value) / MathTrig::FACT($value); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Poisson::distribution($value, $mean, $cumulative); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php new file mode 100644 index 00000000..1ba7adca --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php @@ -0,0 +1,55 @@ +getMessage(); + } + + if (($value < 0) || ($mean < 0)) { + return Functions::NAN(); + } + + if ($cumulative) { + $summer = 0; + $floor = floor($value); + for ($i = 0; $i <= $floor; ++$i) { + $summer += $mean ** $i / MathTrig::FACT($i); + } + + return exp(0 - $mean) * $summer; + } + + return (exp(0 - $mean) * $mean ** $value) / MathTrig::FACT($value); + } +} diff --git a/tests/data/Calculation/Statistical/POISSON.php b/tests/data/Calculation/Statistical/POISSON.php index 11a82cab..7c839ac7 100644 --- a/tests/data/Calculation/Statistical/POISSON.php +++ b/tests/data/Calculation/Statistical/POISSON.php @@ -18,11 +18,23 @@ return [ 35, 40, true, ], [ - '#NUM!', - 35, -40, true, + '#VALUE!', + 'Nan', 40, true, ], [ '#VALUE!', 35, 'Nan', true, ], + [ + '#VALUE!', + 35, 40, 'Nan', + ], + 'Value < 0' => [ + '#NUM!', + -35, 40, true, + ], + 'Mean < 0' => [ + '#NUM!', + 35, -40, true, + ], ]; From 9239b3deca880a0ab66692bd6011b7b89f6274dc Mon Sep 17 00:00:00 2001 From: oleibman Date: Fri, 26 Mar 2021 01:35:30 -0700 Subject: [PATCH 135/187] Continue MathTrig Breakup - Problem Children (#1954) Continuing the process of breaking MathTrip.php up into smaller classes. This round takes care of all functions which might be an impediment to installing due to either uncovered code or "complexity": - BASE - FACT - LCM - MDETERM, MINVERSE, MMULT - MULTINOMIAL - PRODUCT - QUOTIENT - SERIESSUM - SUM - SUMPRODUCT MathTrig and the members in directory MathTrig are now 100% covered. Many tests have been added, and some edge-case bugs are corrected. Some cases where PhpSpreadsheet had rejected numeric values stored as strings have been changed to accept them whenever Excel does; there had been no tests for that condition. Boolean arguments are now accepted as arguments wherever Excel accpets them. Taking a cue from what has been done in Engineering, the parameter validation now happens in a routine which issues Exceptions for invalid values; this simplifies the code in the functions themselves. Thank you for doing that; I did not foresee how useful that was when I first looked at it. Consistent with earlier changes of this nature, the versions in the MathTrig class remain, with a doc block indicating deprecation, and a stub call to the new routines. All tests except for MINVERSE and MMULT are now handled in the context of a spreadsheet rather than a direct call to the calculation function which implements it. PhpSpreadsheet would need to handle dynamic arrays in order to test MINVERSE and MMULT in a spreadsheet context. Implementing that looks like it might be *very* challenging. It is not something I plan to look at, at least not in the near future. One parsing problem turned up in the test conversion. It is in one of the SUMIF tests. It takes me to an area in Calculation where the comment says "I don't even want to know what you did to get here". It did not show up in the previous incarnation because, by using a direct call, the previous test managed to bypass the parsing. I have confirmed that this problem shows up in earlier releases of PhpSpreadsheet, so the changes in this PR did not cause it - they merely exposed it. I have left the test intact, but marked it "incomplete" for documentation purposes. I have not been able to get a handle on what's going wrong yet. I will probably open an issue on it if I can't resolve it soon. However, the test in question isn't a "real world" issue, and the error wasn't caused by this change, so I see no reason to delay this pending a resolution of the problem. SUM had an idiosyncratic moment of its own. It had been ignoring non-numeric values, but Excel returns VALUE in that situation. So I changed it and wrote some new tests, which worked, but ... SUMIF uses several levels of indirection to get to SUM, and SUMIF *does* ignore non-numeric values, so a SUMIF test broke. SUM is a really simple function; the most practical approach seemed to be to clone it, with the string-accepting version being used by the Legacy version (which is called by SUMIF), and the non-string-accepting version being used in the Calculation Function table. That seems far easier and more practical than, for instance, adding a boolean parameter to the variable parameter list. As a follow-up, I will change SUMIF to explicitly call the appropriate new version, but I did not want to add that to this already large change. SUM again - although it was fully covered beforehand, there was not a specific test member for it. There is now. FACT had been coded to fail Gnumeric requests where the numeric argument has a decimal portion. However, Gnumeric does accept such an argument, and, unlike Excel and ODS, does not truncate it, but returns the result of a Gamma function call instead. This has been corrected. When LCM included arguments which contained both 0 and a negative number, it returned 0 or NUM, whichever it found first. It is changed to always return NUM in that circumstance, as Excel does. QUOTIENT had been documented as taking a variadic list of arguments. In fact, it takes exactly 2 - numerator and denominator - and the docblock and signature is fixed, even in the deprecated version. The SERIESSUM docbock and signature are more accurate, even in the deprecated version. It is changed to ignore nulls, as Excel does, rather than return VALUE, and is one of the routines which previously rejected numbers in string form. SUBTOTAL tests had used mocking for some reason. These are replaced with normal tests. And SUBTOTAL had a big surprise in store. That part of it which deals with hidden cells cares only whether the row is hidden, and doesn't care about the column's visibility. I struggled with whether it should be SubTotal or Subtotal. I think the latter is correct, so that's how I proceeded. I don't think there are likely to be any other capitalization controversies. --- .../Calculation/Calculation.php | 24 +- src/PhpSpreadsheet/Calculation/Database.php | 4 +- .../Calculation/Database/DProduct.php | 2 +- .../Calculation/Database/DSum.php | 2 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 494 ++---------------- .../Calculation/MathTrig/Base.php | 49 ++ .../Calculation/MathTrig/Fact.php | 47 ++ .../Calculation/MathTrig/Helpers.php | 28 + .../Calculation/MathTrig/Lcm.php | 95 ++++ .../Calculation/MathTrig/MatrixFunctions.php | 114 ++++ .../Calculation/MathTrig/Multinomial.php | 41 ++ .../Calculation/MathTrig/Product.php | 47 ++ .../Calculation/MathTrig/Quotient.php | 35 ++ .../Calculation/MathTrig/SeriesSum.php | 46 ++ .../Calculation/MathTrig/Subtotal.php | 99 ++++ .../Calculation/MathTrig/Sum.php | 68 +++ .../Calculation/MathTrig/SumProduct.php | 49 ++ .../Calculation/Statistical/Conditional.php | 2 +- .../Functions/MathTrig/AcosTest.php | 13 +- .../Functions/MathTrig/AcoshTest.php | 13 +- .../Functions/MathTrig/AcotTest.php | 13 +- .../Functions/MathTrig/AcothTest.php | 13 +- .../Functions/MathTrig/AllSetupTeardown.php | 52 ++ .../Functions/MathTrig/AsinTest.php | 13 +- .../Functions/MathTrig/AsinhTest.php | 13 +- .../Functions/MathTrig/Atan2Test.php | 13 +- .../Functions/MathTrig/AtanTest.php | 13 +- .../Functions/MathTrig/AtanhTest.php | 13 +- .../Functions/MathTrig/BaseTest.php | 38 +- .../Functions/MathTrig/CeilingMathTest.php | 13 +- .../Functions/MathTrig/CeilingPreciseTest.php | 13 +- .../Functions/MathTrig/CeilingTest.php | 45 +- .../Functions/MathTrig/CosTest.php | 13 +- .../Functions/MathTrig/CoshTest.php | 13 +- .../Functions/MathTrig/CotTest.php | 13 +- .../Functions/MathTrig/CothTest.php | 13 +- .../Functions/MathTrig/CscTest.php | 13 +- .../Functions/MathTrig/CschTest.php | 13 +- .../Functions/MathTrig/EvenTest.php | 13 +- .../Functions/MathTrig/FactTest.php | 57 +- .../Functions/MathTrig/FloorMathTest.php | 13 +- .../Functions/MathTrig/FloorPreciseTest.php | 13 +- .../Functions/MathTrig/FloorTest.php | 43 +- .../Functions/MathTrig/IntTest.php | 13 +- .../Functions/MathTrig/LcmTest.php | 20 +- .../Functions/MathTrig/MInverseTest.php | 17 +- .../Functions/MathTrig/MMultTest.php | 17 +- .../Functions/MathTrig/MRoundTest.php | 13 +- .../Functions/MathTrig/MdeTermTest.php | 26 +- .../Functions/MathTrig/MovedFunctionsTest.php | 21 + .../Functions/MathTrig/MultinomialTest.php | 25 +- .../Functions/MathTrig/OddTest.php | 13 +- .../Functions/MathTrig/ProductTest.php | 20 +- .../Functions/MathTrig/QuotientTest.php | 34 +- .../Functions/MathTrig/RomanTest.php | 20 +- .../Functions/MathTrig/RoundDownTest.php | 13 +- .../Functions/MathTrig/RoundTest.php | 13 +- .../Functions/MathTrig/RoundUpTest.php | 13 +- .../Functions/MathTrig/SecTest.php | 13 +- .../Functions/MathTrig/SechTest.php | 13 +- .../Functions/MathTrig/SeriesSumTest.php | 35 +- .../Functions/MathTrig/SignTest.php | 13 +- .../Functions/MathTrig/SinTest.php | 13 +- .../Functions/MathTrig/SinhTest.php | 13 +- .../Functions/MathTrig/SubTotalTest.php | 258 ++++----- .../Functions/MathTrig/SumIfTest.php | 35 +- .../Functions/MathTrig/SumProductTest.php | 28 +- .../Functions/MathTrig/SumTest.php | 29 + .../Functions/MathTrig/TanTest.php | 13 +- .../Functions/MathTrig/TanhTest.php | 13 +- .../Functions/MathTrig/TruncTest.php | 13 +- tests/data/Calculation/MathTrig/BASE.php | 6 + tests/data/Calculation/MathTrig/FACT.php | 4 +- .../Calculation/MathTrig/FACTGNUMERIC.php | 44 ++ tests/data/Calculation/MathTrig/LCM.php | 5 + tests/data/Calculation/MathTrig/MDETERM.php | 34 +- tests/data/Calculation/MathTrig/MINVERSE.php | 28 + tests/data/Calculation/MathTrig/MMULT.php | 22 + .../data/Calculation/MathTrig/MULTINOMIAL.php | 6 + tests/data/Calculation/MathTrig/PRODUCT.php | 2 + tests/data/Calculation/MathTrig/QUOTIENT.php | 8 + tests/data/Calculation/MathTrig/SERIESSUM.php | 12 + tests/data/Calculation/MathTrig/SUBTOTAL.php | 85 +-- .../Calculation/MathTrig/SUBTOTALHIDDEN.php | 107 +--- .../Calculation/MathTrig/SUBTOTALNESTED.php | 18 - tests/data/Calculation/MathTrig/SUM.php | 8 + tests/data/Calculation/MathTrig/SUMIF.php | 30 +- .../data/Calculation/MathTrig/SUMPRODUCT.php | 10 + 88 files changed, 1559 insertions(+), 1378 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Base.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Fact.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Multinomial.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Product.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Quotient.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/SeriesSum.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sum.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/SumProduct.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php create mode 100644 tests/data/Calculation/MathTrig/FACTGNUMERIC.php delete mode 100644 tests/data/Calculation/MathTrig/SUBTOTALNESTED.php create mode 100644 tests/data/Calculation/MathTrig/SUM.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 792402ce..3cce499f 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -358,7 +358,7 @@ class Calculation ], 'BASE' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'BASE'], + 'functionCall' => [MathTrig\Base::class, 'funcBase'], 'argumentCount' => '2,3', ], 'BESSELI' => [ @@ -990,7 +990,7 @@ class Calculation ], 'FACT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'FACT'], + 'functionCall' => [MathTrig\Fact::class, 'funcFact'], 'argumentCount' => '1', ], 'FACTDOUBLE' => [ @@ -1536,7 +1536,7 @@ class Calculation ], 'LCM' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'LCM'], + 'functionCall' => [MathTrig\Lcm::class, 'funcLcm'], 'argumentCount' => '1+', ], 'LEFT' => [ @@ -1636,7 +1636,7 @@ class Calculation ], 'MDETERM' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'MDETERM'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMDeterm'], 'argumentCount' => '1', ], 'MDURATION' => [ @@ -1686,7 +1686,7 @@ class Calculation ], 'MINVERSE' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'MINVERSE'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMinverse'], 'argumentCount' => '1', ], 'MIRR' => [ @@ -1696,7 +1696,7 @@ class Calculation ], 'MMULT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'MMULT'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMMult'], 'argumentCount' => '2', ], 'MOD' => [ @@ -1731,7 +1731,7 @@ class Calculation ], 'MULTINOMIAL' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'MULTINOMIAL'], + 'functionCall' => [MathTrig\Multinomial::class, 'funcMultinomial'], 'argumentCount' => '1+', ], 'MUNIT' => [ @@ -2003,7 +2003,7 @@ class Calculation ], 'PRODUCT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'PRODUCT'], + 'functionCall' => [MathTrig\Product::class, 'funcProduct'], 'argumentCount' => '1+', ], 'PROPER' => [ @@ -2033,7 +2033,7 @@ class Calculation ], 'QUOTIENT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'QUOTIENT'], + 'functionCall' => [MathTrig\Quotient::class, 'funcQuotient'], 'argumentCount' => '2', ], 'RADIANS' => [ @@ -2305,13 +2305,13 @@ class Calculation ], 'SUBTOTAL' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUBTOTAL'], + 'functionCall' => [MathTrig\Subtotal::class, 'funcSubtotal'], 'argumentCount' => '2+', 'passCellReference' => true, ], 'SUM' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUM'], + 'functionCall' => [MathTrig\Sum::class, 'funcSumNoStrings'], 'argumentCount' => '1+', ], 'SUMIF' => [ @@ -2326,7 +2326,7 @@ class Calculation ], 'SUMPRODUCT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMPRODUCT'], + 'functionCall' => [MathTrig\SumProduct::class, 'funcSumProduct'], 'argumentCount' => '1+', ], 'SUMSQ' => [ diff --git a/src/PhpSpreadsheet/Calculation/Database.php b/src/PhpSpreadsheet/Calculation/Database.php index 76431979..a4c4d7d2 100644 --- a/src/PhpSpreadsheet/Calculation/Database.php +++ b/src/PhpSpreadsheet/Calculation/Database.php @@ -245,7 +245,7 @@ class Database * the column label in which you specify a condition for the * column. * - * @return float + * @return float|string */ public static function DPRODUCT($database, $field, $criteria) { @@ -349,7 +349,7 @@ class Database * the column label in which you specify a condition for the * column. * - * @return float + * @return float|string */ public static function DSUM($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DProduct.php b/src/PhpSpreadsheet/Calculation/Database/DProduct.php index a3b245f3..107c69c0 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DProduct.php +++ b/src/PhpSpreadsheet/Calculation/Database/DProduct.php @@ -29,7 +29,7 @@ class DProduct extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float + * @return float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DSum.php b/src/PhpSpreadsheet/Calculation/Database/DSum.php index b2fa464a..473bacd1 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DSum.php +++ b/src/PhpSpreadsheet/Calculation/Database/DSum.php @@ -29,7 +29,7 @@ class DSum extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float + * @return float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 94850906..1dbc2854 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -3,37 +3,9 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; use Exception; -use Matrix\Exception as MatrixException; -use Matrix\Matrix; class MathTrig { - // - // Private method to return an array of the factors of the input value - // - private static function factors($value) - { - $startVal = floor(sqrt($value)); - - $factorArray = []; - for ($i = $startVal; $i > 1; --$i) { - if (($value % $i) == 0) { - $factorArray = array_merge($factorArray, self::factors($value / $i)); - $factorArray = array_merge($factorArray, self::factors($i)); - if ($i <= sqrt($value)) { - break; - } - } - } - if (!empty($factorArray)) { - rsort($factorArray); - - return $factorArray; - } - - return [(int) $value]; - } - private static function strSplit(string $roman): array { $rslt = str_split($roman); @@ -153,6 +125,8 @@ class MathTrig * * Converts a number into a text representation with the given radix (base). * + * @Deprecated 2.0.0 Use the funcBase method in the MathTrig\Base class instead + * * Excel Function: * BASE(Number, Radix [Min_length]) * @@ -164,29 +138,7 @@ class MathTrig */ public static function BASE($number, $radix, $minLength = null) { - $number = Functions::flattenSingleValue($number); - $radix = Functions::flattenSingleValue($radix); - $minLength = Functions::flattenSingleValue($minLength); - - if (is_numeric($number) && is_numeric($radix) && ($minLength === null || is_numeric($minLength))) { - // Truncate to an integer - $number = (int) $number; - $radix = (int) $radix; - $minLength = (int) $minLength; - - if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) { - return Functions::NAN(); // Numeric range constraints - } - - $outcome = strtoupper((string) base_convert($number, 10, $radix)); - if ($minLength !== null) { - $outcome = str_pad($outcome, $minLength, '0', STR_PAD_LEFT); // String padding - } - - return $outcome; - } - - return Functions::VALUE(); + return MathTrig\Base::funcBase($number, $radix, $minLength); } /** @@ -240,7 +192,7 @@ class MathTrig return Functions::NAN(); } - return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet); + return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)) / MathTrig\Fact::funcFact($numInSet); } return Functions::VALUE(); @@ -285,6 +237,8 @@ class MathTrig * Returns the factorial of a number. * The factorial of a number is equal to 1*2*3*...* number. * + * @Deprecated 2.0.0 Use the funcFact method in the MathTrig\Fact class instead + * * Excel Function: * FACT(factVal) * @@ -294,29 +248,7 @@ class MathTrig */ public static function FACT($factVal) { - $factVal = Functions::flattenSingleValue($factVal); - - if (is_numeric($factVal)) { - if ($factVal < 0) { - return Functions::NAN(); - } - $factLoop = floor($factVal); - if ( - (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) && - ($factVal > $factLoop) - ) { - return Functions::NAN(); - } - - $factorial = 1; - while ($factLoop > 1) { - $factorial *= $factLoop--; - } - - return $factorial; - } - - return Functions::VALUE(); + return MathTrig\Fact::funcFact($factVal); } /** @@ -487,6 +419,8 @@ class MathTrig * of all integer arguments number1, number2, and so on. Use LCM to add fractions * with different denominators. * + * @Deprecated 2.0.0 Use the funcLcm method in the MathTrig\Lcm class instead + * * Excel Function: * LCM(number1[,number2[, ...]]) * @@ -496,39 +430,7 @@ class MathTrig */ public static function LCM(...$args) { - $returnValue = 1; - $allPoweredFactors = []; - // Loop through arguments - foreach (Functions::flattenArray($args) as $value) { - if (!is_numeric($value)) { - return Functions::VALUE(); - } - if ($value == 0) { - return 0; - } elseif ($value < 0) { - return Functions::NAN(); - } - $myFactors = self::factors(floor($value)); - $myCountedFactors = array_count_values($myFactors); - $myPoweredFactors = []; - foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) { - $myPoweredFactors[$myCountedFactor] = $myCountedFactor ** $myCountedPower; - } - foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) { - if (isset($allPoweredFactors[$myPoweredValue])) { - if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) { - $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; - } - } else { - $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; - } - } - } - foreach ($allPoweredFactors as $allPoweredFactor) { - $returnValue *= (int) $allPoweredFactor; - } - - return $returnValue; + return MathTrig\Lcm::funcLcm(...$args); } /** @@ -564,6 +466,8 @@ class MathTrig * * Returns the matrix determinant of an array. * + * @Deprecated 2.0.0 Use the funcMDeterm method in the MathTrig\MatrixFuncs class instead + * * Excel Function: * MDETERM(array) * @@ -573,40 +477,7 @@ class MathTrig */ public static function MDETERM($matrixValues) { - $matrixData = []; - if (!is_array($matrixValues)) { - $matrixValues = [[$matrixValues]]; - } - - $row = $maxColumn = 0; - foreach ($matrixValues as $matrixRow) { - if (!is_array($matrixRow)) { - $matrixRow = [$matrixRow]; - } - $column = 0; - foreach ($matrixRow as $matrixCell) { - if ((is_string($matrixCell)) || ($matrixCell === null)) { - return Functions::VALUE(); - } - $matrixData[$row][$column] = $matrixCell; - ++$column; - } - if ($column > $maxColumn) { - $maxColumn = $column; - } - ++$row; - } - - $matrix = new Matrix($matrixData); - if (!$matrix->isSquare()) { - return Functions::VALUE(); - } - - try { - return $matrix->determinant(); - } catch (MatrixException $ex) { - return Functions::VALUE(); - } + return MathTrig\MatrixFunctions::funcMDeterm($matrixValues); } /** @@ -614,6 +485,8 @@ class MathTrig * * Returns the inverse matrix for the matrix stored in an array. * + * @Deprecated 2.0.0 Use the funcMInverse method in the MathTrig\MatrixFuncs class instead + * * Excel Function: * MINVERSE(array) * @@ -623,49 +496,14 @@ class MathTrig */ public static function MINVERSE($matrixValues) { - $matrixData = []; - if (!is_array($matrixValues)) { - $matrixValues = [[$matrixValues]]; - } - - $row = $maxColumn = 0; - foreach ($matrixValues as $matrixRow) { - if (!is_array($matrixRow)) { - $matrixRow = [$matrixRow]; - } - $column = 0; - foreach ($matrixRow as $matrixCell) { - if ((is_string($matrixCell)) || ($matrixCell === null)) { - return Functions::VALUE(); - } - $matrixData[$row][$column] = $matrixCell; - ++$column; - } - if ($column > $maxColumn) { - $maxColumn = $column; - } - ++$row; - } - - $matrix = new Matrix($matrixData); - if (!$matrix->isSquare()) { - return Functions::VALUE(); - } - - if ($matrix->determinant() == 0.0) { - return Functions::NAN(); - } - - try { - return $matrix->inverse()->toArray(); - } catch (MatrixException $ex) { - return Functions::VALUE(); - } + return MathTrig\MatrixFunctions::funcMInverse($matrixValues); } /** * MMULT. * + * @Deprecated 2.0.0 Use the funcMMult method in the MathTrig\MatrixFuncs class instead + * * @param array $matrixData1 A matrix of values * @param array $matrixData2 A matrix of values * @@ -673,56 +511,7 @@ class MathTrig */ public static function MMULT($matrixData1, $matrixData2) { - $matrixAData = $matrixBData = []; - if (!is_array($matrixData1)) { - $matrixData1 = [[$matrixData1]]; - } - if (!is_array($matrixData2)) { - $matrixData2 = [[$matrixData2]]; - } - - try { - $rowA = 0; - foreach ($matrixData1 as $matrixRow) { - if (!is_array($matrixRow)) { - $matrixRow = [$matrixRow]; - } - $columnA = 0; - foreach ($matrixRow as $matrixCell) { - if ((!is_numeric($matrixCell)) || ($matrixCell === null)) { - return Functions::VALUE(); - } - $matrixAData[$rowA][$columnA] = $matrixCell; - ++$columnA; - } - ++$rowA; - } - $matrixA = new Matrix($matrixAData); - $rowB = 0; - foreach ($matrixData2 as $matrixRow) { - if (!is_array($matrixRow)) { - $matrixRow = [$matrixRow]; - } - $columnB = 0; - foreach ($matrixRow as $matrixCell) { - if ((!is_numeric($matrixCell)) || ($matrixCell === null)) { - return Functions::VALUE(); - } - $matrixBData[$rowB][$columnB] = $matrixCell; - ++$columnB; - } - ++$rowB; - } - $matrixB = new Matrix($matrixBData); - - if ($columnA != $rowB) { - return Functions::VALUE(); - } - - return $matrixA->multiply($matrixB)->toArray(); - } catch (MatrixException $ex) { - return Functions::VALUE(); - } + return MathTrig\MatrixFunctions::funcMMult($matrixData1, $matrixData2); } /** @@ -779,30 +568,7 @@ class MathTrig */ public static function MULTINOMIAL(...$args) { - $summer = 0; - $divisor = 1; - // Loop through arguments - foreach (Functions::flattenArray($args) as $arg) { - // Is it a numeric value? - if (is_numeric($arg)) { - if ($arg < 1) { - return Functions::NAN(); - } - $summer += floor($arg); - $divisor *= self::FACT($arg); - } else { - return Functions::VALUE(); - } - } - - // Return - if ($summer > 0) { - $summer = self::FACT($summer); - - return $summer / $divisor; - } - - return 0; + return MathTrig\Multinomial::funcMultinomial(...$args); } /** @@ -854,36 +620,18 @@ class MathTrig * * PRODUCT returns the product of all the values and cells referenced in the argument list. * + * @Deprecated 2.0.0 Use the funcProduct method in the MathTrig\Product class instead + * * Excel Function: * PRODUCT(value1[,value2[, ...]]) * * @param mixed ...$args Data values * - * @return float + * @return float|string */ public static function PRODUCT(...$args) { - // Return value - $returnValue = null; - - // Loop through arguments - foreach (Functions::flattenArray($args) as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ($returnValue === null) { - $returnValue = $arg; - } else { - $returnValue *= $arg; - } - } - } - - // Return - if ($returnValue === null) { - return 0; - } - - return $returnValue; + return MathTrig\Product::funcProduct(...$args); } /** @@ -892,36 +640,19 @@ class MathTrig * QUOTIENT function returns the integer portion of a division. Numerator is the divided number * and denominator is the divisor. * + * @Deprecated 2.0.0 Use the funcQuotient method in the MathTrig\Quotient class instead + * * Excel Function: * QUOTIENT(value1[,value2[, ...]]) * - * @param mixed ...$args Data values + * @param mixed $numerator + * @param mixed $denominator * - * @return float + * @return int|string */ - public static function QUOTIENT(...$args) + public static function QUOTIENT($numerator, $denominator) { - // Return value - $returnValue = null; - - // Loop through arguments - foreach (Functions::flattenArray($args) as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - if ($returnValue === null) { - $returnValue = ($arg == 0) ? 0 : $arg; - } else { - if (($returnValue == 0) || ($arg == 0)) { - $returnValue = 0; - } else { - $returnValue /= $arg; - } - } - } - } - - // Return - return (int) $returnValue; + return MathTrig\Quotient::funcQuotient($numerator, $denominator); } /** @@ -1006,37 +737,18 @@ class MathTrig * * Returns the sum of a power series * - * @param mixed[] $args An array of mixed values for the Data Series + * @Deprecated 2.0.0 Use the funcSeriesSum method in the MathTrig\SeriesSum class instead + * + * @param mixed $x Input value + * @param mixed $n Initial power + * @param mixed $m Step + * @param mixed[] $args An array of coefficients for the Data Series * * @return float|string The result, or a string containing an error */ - public static function SERIESSUM(...$args) + public static function SERIESSUM($x, $n, $m, ...$args) { - $returnValue = 0; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - - $x = array_shift($aArgs); - $n = array_shift($aArgs); - $m = array_shift($aArgs); - - if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) { - // Calculate - $i = 0; - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += $arg * $x ** ($n + ($m * $i++)); - } else { - return Functions::VALUE(); - } - } - - return $returnValue; - } - - return Functions::VALUE(); + return MathTrig\SeriesSum::funcSeriesSum($x, $n, $m, ...$args); } /** @@ -1090,45 +802,13 @@ class MathTrig return Functions::VALUE(); } - protected static function filterHiddenArgs($cellReference, $args) - { - return array_filter( - $args, - function ($index) use ($cellReference) { - [, $row, $column] = explode('.', $index); - - return $cellReference->getWorksheet()->getRowDimension($row)->getVisible() && - $cellReference->getWorksheet()->getColumnDimension($column)->getVisible(); - }, - ARRAY_FILTER_USE_KEY - ); - } - - protected static function filterFormulaArgs($cellReference, $args) - { - return array_filter( - $args, - function ($index) use ($cellReference) { - [, $row, $column] = explode('.', $index); - if ($cellReference->getWorksheet()->cellExists($column . $row)) { - //take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula - $isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula(); - $cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue()); - - return !$isFormula || $cellFormula; - } - - return true; - }, - ARRAY_FILTER_USE_KEY - ); - } - /** * SUBTOTAL. * * Returns a subtotal in a list or database. * + * @Deprecated 2.0.0 Use the funcSubtotal method in the MathTrig\Subtotal class instead + * * @param int $functionType * A number 1 to 11 that specifies which function to * use in calculating subtotals within a range @@ -1142,45 +822,7 @@ class MathTrig */ public static function SUBTOTAL($functionType, ...$args) { - $cellReference = array_pop($args); - $aArgs = Functions::flattenArrayIndexed($args); - $subtotal = Functions::flattenSingleValue($functionType); - - // Calculate - if ((is_numeric($subtotal)) && (!is_string($subtotal))) { - if ($subtotal > 100) { - $aArgs = self::filterHiddenArgs($cellReference, $aArgs); - $subtotal -= 100; - } - - $aArgs = self::filterFormulaArgs($cellReference, $aArgs); - switch ($subtotal) { - case 1: - return Statistical\Averages::average($aArgs); - case 2: - return Statistical\Counts::COUNT($aArgs); - case 3: - return Statistical\Counts::COUNTA($aArgs); - case 4: - return Statistical\Maximum::MAX($aArgs); - case 5: - return Statistical\Minimum::MIN($aArgs); - case 6: - return self::PRODUCT($aArgs); - case 7: - return Statistical\StandardDeviations::STDEV($aArgs); - case 8: - return Statistical\StandardDeviations::STDEVP($aArgs); - case 9: - return self::SUM($aArgs); - case 10: - return Statistical\Variances::VAR($aArgs); - case 11: - return Statistical\Variances::VARP($aArgs); - } - } - - return Functions::VALUE(); + return MathTrig\Subtotal::funcSubtotal($functionType, ...$args); } /** @@ -1188,28 +830,18 @@ class MathTrig * * SUM computes the sum of all the values and cells referenced in the argument list. * + * @Deprecated 2.0.0 Use the funcSumNoStrings method in the MathTrig\Sum class instead + * * Excel Function: * SUM(value1[,value2[, ...]]) * * @param mixed ...$args Data values * - * @return float + * @return float|string */ public static function SUM(...$args) { - $returnValue = 0; - - // Loop through the arguments - foreach (Functions::flattenArray($args) as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += $arg; - } elseif (Functions::isError($arg)) { - return $arg; - } - } - - return $returnValue; + return MathTrig\Sum::funcSum(...$args); } /** @@ -1229,7 +861,7 @@ class MathTrig * @param string $criteria the criteria that defines which cells will be summed * @param mixed $sumRange * - * @return float + * @return float|string */ public static function SUMIF($range, $criteria, $sumRange = []) { @@ -1251,7 +883,7 @@ class MathTrig * * @param mixed $args Data values * - * @return float + * @return float|string */ public static function SUMIFS(...$args) { @@ -1264,39 +896,15 @@ class MathTrig * Excel Function: * SUMPRODUCT(value1[,value2[, ...]]) * + * @Deprecated 2.0.0 Use the funcSumProduct method in the MathTrig\SumProduct class instead + * * @param mixed ...$args Data values * * @return float|string The result, or a string containing an error */ public static function SUMPRODUCT(...$args) { - $arrayList = $args; - - $wrkArray = Functions::flattenArray(array_shift($arrayList)); - $wrkCellCount = count($wrkArray); - - for ($i = 0; $i < $wrkCellCount; ++$i) { - if ((!is_numeric($wrkArray[$i])) || (is_string($wrkArray[$i]))) { - $wrkArray[$i] = 0; - } - } - - foreach ($arrayList as $matrixData) { - $array2 = Functions::flattenArray($matrixData); - $count = count($array2); - if ($wrkCellCount != $count) { - return Functions::VALUE(); - } - - foreach ($array2 as $i => $val) { - if ((!is_numeric($val)) || (is_string($val))) { - $val = 0; - } - $wrkArray[$i] *= $val; - } - } - - return array_sum($wrkArray); + return MathTrig\SumProduct::funcSumProduct(...$args); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Base.php b/src/PhpSpreadsheet/Calculation/MathTrig/Base.php new file mode 100644 index 00000000..35522334 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Base.php @@ -0,0 +1,49 @@ +getMessage(); + } + $minLength = Functions::flattenSingleValue($minLength); + + if ($minLength === null || is_numeric($minLength)) { + if ($number < 0 || $number >= 2 ** 53 || $radix < 2 || $radix > 36) { + return Functions::NAN(); // Numeric range constraints + } + + $outcome = strtoupper((string) base_convert($number, 10, $radix)); + if ($minLength !== null) { + $outcome = str_pad($outcome, (int) $minLength, '0', STR_PAD_LEFT); // String padding + } + + return $outcome; + } + + return Functions::VALUE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php b/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php new file mode 100644 index 00000000..0d591b77 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php @@ -0,0 +1,47 @@ +getMessage(); + } + + $factLoop = floor($factVal); + if ($factVal > $factLoop) { + if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { + return Statistical::GAMMAFunction($factVal + 1); + } + } + + $factorial = 1; + while ($factLoop > 1) { + $factorial *= $factLoop--; + } + + return $factorial; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php index 63b5082c..7abcf050 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php @@ -61,6 +61,34 @@ class Helpers throw new Exception(Functions::VALUE()); } + /** + * Confirm number >= 0. + * + * @param float|int $number + */ + public static function validateNotNegative($number): void + { + if ($number >= 0) { + return; + } + + throw new Exception(Functions::NAN()); + } + + /** + * Confirm number != 0. + * + * @param float|int $number + */ + public static function validateNotZero($number): void + { + if ($number) { + return; + } + + throw new Exception(Functions::DIV0()); + } + public static function returnSign(float $number): int { return $number ? (($number > 0) ? 1 : -1) : 0; diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php b/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php new file mode 100644 index 00000000..3d3f0e46 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php @@ -0,0 +1,95 @@ + 1; --$i) { + if (($value % $i) == 0) { + $factorArray = array_merge($factorArray, self::factors($value / $i)); + $factorArray = array_merge($factorArray, self::factors($i)); + if ($i <= sqrt($value)) { + break; + } + } + } + if (!empty($factorArray)) { + rsort($factorArray); + + return $factorArray; + } + + return [(int) $value]; + } + + /** + * LCM. + * + * Returns the lowest common multiplier of a series of numbers + * The least common multiple is the smallest positive integer that is a multiple + * of all integer arguments number1, number2, and so on. Use LCM to add fractions + * with different denominators. + * + * Excel Function: + * LCM(number1[,number2[, ...]]) + * + * @param mixed ...$args Data values + * + * @return int|string Lowest Common Multiplier, or a string containing an error + */ + public static function funcLcm(...$args) + { + try { + $arrayArgs = []; + $anyZeros = 0; + foreach (Functions::flattenArray($args) as $value1) { + $value = Helpers::validateNumericNullSubstitution($value1, 1); + Helpers::validateNotNegative($value); + $arrayArgs[] = (int) $value; + $anyZeros += (int) !((bool) $value); + } + if ($anyZeros) { + return 0; + } + } catch (Exception $e) { + return $e->getMessage(); + } + + $returnValue = 1; + $allPoweredFactors = []; + // Loop through arguments + foreach ($arrayArgs as $value) { + $myFactors = self::factors(floor($value)); + $myCountedFactors = array_count_values($myFactors); + $myPoweredFactors = []; + foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) { + $myPoweredFactors[$myCountedFactor] = $myCountedFactor ** $myCountedPower; + } + foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) { + if (isset($allPoweredFactors[$myPoweredValue])) { + if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) { + $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; + } + } else { + $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; + } + } + } + foreach ($allPoweredFactors as $allPoweredFactor) { + $returnValue *= (int) $allPoweredFactor; + } + + return $returnValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php b/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php new file mode 100644 index 00000000..77c8b1e1 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php @@ -0,0 +1,114 @@ +determinant(); + } catch (MatrixException $ex) { + return Functions::VALUE(); + } catch (Exception $e) { + return $e->getMessage(); + } + } + + /** + * MINVERSE. + * + * Returns the inverse matrix for the matrix stored in an array. + * + * Excel Function: + * MINVERSE(array) + * + * @param mixed $matrixValues A matrix of values + * + * @return array|string The result, or a string containing an error + */ + public static function funcMInverse($matrixValues) + { + try { + $matrix = self::getMatrix($matrixValues); + + return $matrix->inverse()->toArray(); + } catch (MatrixException $e) { + return (strpos($e->getMessage(), 'determinant') === false) ? Functions::VALUE() : Functions::NAN(); + } catch (Exception $e) { + return $e->getMessage(); + } + } + + /** + * MMULT. + * + * @param mixed $matrixData1 A matrix of values + * @param mixed $matrixData2 A matrix of values + * + * @return array|string The result, or a string containing an error + */ + public static function funcMMult($matrixData1, $matrixData2) + { + try { + $matrixA = self::getMatrix($matrixData1); + $matrixB = self::getMatrix($matrixData2); + + return $matrixA->multiply($matrixB)->toArray(); + } catch (MatrixException $ex) { + return Functions::VALUE(); + } catch (Exception $e) { + return $e->getMessage(); + } + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Multinomial.php b/src/PhpSpreadsheet/Calculation/MathTrig/Multinomial.php new file mode 100644 index 00000000..5ebecb97 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Multinomial.php @@ -0,0 +1,41 @@ +getMessage(); + } + + $summer = Fact::funcFact($summer); + + return $summer / $divisor; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Product.php b/src/PhpSpreadsheet/Calculation/MathTrig/Product.php new file mode 100644 index 00000000..254b7b79 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Product.php @@ -0,0 +1,47 @@ +getMessage(); + } + + return (int) ($numerator / $denominator); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/SeriesSum.php b/src/PhpSpreadsheet/Calculation/MathTrig/SeriesSum.php new file mode 100644 index 00000000..063593b6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/SeriesSum.php @@ -0,0 +1,46 @@ +getMessage(); + } + + return $returnValue; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php b/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php new file mode 100644 index 00000000..3d441fa2 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php @@ -0,0 +1,99 @@ +getWorksheet()->getRowDimension($row)->getVisible(); + }, + ARRAY_FILTER_USE_KEY + ); + } + + protected static function filterFormulaArgs($cellReference, $args) + { + return array_filter( + $args, + function ($index) use ($cellReference) { + [, $row, $column] = explode('.', $index); + $retVal = true; + if ($cellReference->getWorksheet()->cellExists($column . $row)) { + //take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula + $isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula(); + $cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue()); + + $retVal = !$isFormula || $cellFormula; + } + + return $retVal; + }, + ARRAY_FILTER_USE_KEY + ); + } + + private const CALL_FUNCTIONS = [ + 1 => [Statistical\Averages::class, 'AVERAGE'], + [Statistical\Counts::class, 'COUNT'], // 2 + [Statistical\Counts::class, 'COUNTA'], // 3 + [Statistical\Maximum::class, 'MAX'], // 4 + [Statistical\Minimum::class, 'MIN'], // 5 + [Product::class, 'funcProduct'], // 6 + [Statistical\StandardDeviations::class, 'STDEV'], // 7 + [Statistical\StandardDeviations::class, 'STDEVP'], // 8 + [Sum::class, 'funcSum'], // 9 + [Statistical\Variances::class, 'VAR'], // 10 + [Statistical\Variances::class, 'VARP'], // 11 + ]; + + /** + * SUBTOTAL. + * + * Returns a subtotal in a list or database. + * + * @param mixed $functionType + * A number 1 to 11 that specifies which function to + * use in calculating subtotals within a range + * list + * Numbers 101 to 111 shadow the functions of 1 to 11 + * but ignore any values in the range that are + * in hidden rows or columns + * @param mixed[] $args A mixed data series of values + * + * @return float|string + */ + public static function funcSubtotal($functionType, ...$args) + { + $cellReference = array_pop($args); + $aArgs = Functions::flattenArrayIndexed($args); + + try { + $subtotal = (int) Helpers::validateNumericNullBool($functionType); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Calculate + if ($subtotal > 100) { + $aArgs = self::filterHiddenArgs($cellReference, $aArgs); + $subtotal -= 100; + } + + $aArgs = self::filterFormulaArgs($cellReference, $aArgs); + if (array_key_exists($subtotal, self::CALL_FUNCTIONS)) { + return call_user_func_array(self::CALL_FUNCTIONS[$subtotal], $aArgs); + } + + return Functions::VALUE(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php new file mode 100644 index 00000000..cd29248b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sum.php @@ -0,0 +1,68 @@ + $val) { + if ((!is_numeric($val)) || (is_string($val))) { + $val = 0; + } + $wrkArray[$i] *= $val; + } + } + + return array_sum($wrkArray); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php index 7ed1e714..51e6b004 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Conditional.php @@ -178,7 +178,7 @@ class Conditional * @param mixed $sumRange * @param mixed $condition * - * @return float + * @return float|string */ public static function SUMIF($range, $condition, $sumRange = []) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php index 9dd6a49d..f9bdac46 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AcosTest extends TestCase +class AcosTest extends AllSetupTeardown { /** * @dataProvider providerAcos @@ -15,11 +11,8 @@ class AcosTest extends TestCase */ public function testAcos($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue(0.5); $sheet->getCell('A1')->setValue("=ACOS($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php index d596cc9e..40930582 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AcoshTest extends TestCase +class AcoshTest extends AllSetupTeardown { /** * @dataProvider providerAcosh @@ -15,11 +11,8 @@ class AcoshTest extends TestCase */ public function testAcosh($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue('1.5'); $sheet->getCell('A1')->setValue("=ACOSH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php index 99694215..de9e2196 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AcotTest extends TestCase +class AcotTest extends AllSetupTeardown { /** * @dataProvider providerACOT @@ -16,11 +12,8 @@ class AcotTest extends TestCase */ public function testACOT($expectedResult, $number): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php index 1d565e73..f28064f8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AcothTest extends TestCase +class AcothTest extends AllSetupTeardown { /** * @dataProvider providerACOTH @@ -16,11 +12,8 @@ class AcothTest extends TestCase */ public function testACOTH($expectedResult, $number): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php new file mode 100644 index 00000000..86c30c22 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php @@ -0,0 +1,52 @@ +compatibilityMode = Functions::getCompatibilityMode(); + $this->spreadsheet = new Spreadsheet(); + $this->sheet = $this->spreadsheet->getActiveSheet(); + } + + protected function tearDown(): void + { + Functions::setCompatibilityMode($this->compatibilityMode); + $this->spreadsheet->disconnectWorksheets(); + $this->spreadsheet = null; + $this->sheet = null; + } + + protected static function setOpenOffice(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + } + + protected static function setGnumeric(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); + } + + /** + * @param mixed $expectedResult + */ + protected function mightHaveException($expectedResult): void + { + if ($expectedResult === 'exception') { + $this->expectException(CalcException::class); + } + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php index c1c836f3..4797a93f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AsinTest extends TestCase +class AsinTest extends AllSetupTeardown { /** * @dataProvider providerAsin @@ -15,11 +11,8 @@ class AsinTest extends TestCase */ public function testAsin($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue(0.5); $sheet->getCell('A1')->setValue("=ASIN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php index ebbb74f1..3f63a01c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AsinhTest extends TestCase +class AsinhTest extends AllSetupTeardown { /** * @dataProvider providerAsinh @@ -15,11 +11,8 @@ class AsinhTest extends TestCase */ public function testAsinh($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue(0.5); $sheet->getCell('A1')->setValue("=ASINH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php index 35a96aea..e1d435de 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class Atan2Test extends TestCase +class Atan2Test extends AllSetupTeardown { /** * @dataProvider providerATAN2 @@ -15,11 +11,8 @@ class Atan2Test extends TestCase */ public function testATAN2($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue(5); $sheet->getCell('A3')->setValue(6); $sheet->getCell('A1')->setValue("=ATAN2($formula)"); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php index 4dec2dca..c92f834a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AtanTest extends TestCase +class AtanTest extends AllSetupTeardown { /** * @dataProvider providerAtan @@ -15,11 +11,8 @@ class AtanTest extends TestCase */ public function testAtan($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue(5); $sheet->getCell('A1')->setValue("=ATAN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php index cc8a243f..abefd334 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AtanhTest extends TestCase +class AtanhTest extends AllSetupTeardown { /** * @dataProvider providerAtanh @@ -15,11 +11,8 @@ class AtanhTest extends TestCase */ public function testAtanh($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A2')->setValue(0.8); $sheet->getCell('A1')->setValue("=ATANH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php index 72b52559..94176c77 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php @@ -2,25 +2,39 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class BaseTest extends TestCase +class BaseTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerBASE * * @param mixed $expectedResult + * @param mixed $arg1 + * @param mixed $arg2 + * @param mixed $arg3 */ - public function testBASE($expectedResult, ...$args): void + public function testBASE($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', $arg3 = 'omitted'): void { - $result = MathTrig::BASE(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg2 !== null) { + $sheet->getCell('A2')->setValue($arg2); + } + if ($arg3 !== null) { + $sheet->getCell('A3')->setValue($arg3); + } + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=BASE()'); + } elseif ($arg2 === 'omitted') { + $sheet->getCell('B1')->setValue('=BASE(A1)'); + } elseif ($arg3 === 'omitted') { + $sheet->getCell('B1')->setValue('=BASE(A1, A2)'); + } else { + $sheet->getCell('B1')->setValue('=BASE(A1, A2, A3)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEquals($expectedResult, $result); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php index 1d62b8c3..cd1dcb33 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CeilingMathTest extends TestCase +class CeilingMathTest extends AllSetupTeardown { /** * @dataProvider providerCEILINGMATH @@ -16,11 +12,8 @@ class CeilingMathTest extends TestCase */ public function testCEILINGMATH($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php index d47670b7..7c9e289e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CeilingPreciseTest extends TestCase +class CeilingPreciseTest extends AllSetupTeardown { /** * @dataProvider providerFLOORPRECISE @@ -16,11 +12,8 @@ class CeilingPreciseTest extends TestCase */ public function testCEILINGPRECISE($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php index ad99b5f0..bbbc10ea 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php @@ -2,26 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CeilingTest extends TestCase +class CeilingTest extends AllSetupTeardown { - private $compatibilityMode; - - protected function setUp(): void - { - $this->compatibilityMode = Functions::getCompatibilityMode(); - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - - protected function tearDown(): void - { - Functions::setCompatibilityMode($this->compatibilityMode); - } - /** * @dataProvider providerCEILING * @@ -30,11 +12,8 @@ class CeilingTest extends TestCase */ public function testCEILING($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); @@ -51,9 +30,8 @@ class CeilingTest extends TestCase public function testCEILINGGnumeric1Arg(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + self::setGnumeric(); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=CEILING(5.1)'); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta(6, $result, 1E-12); @@ -61,20 +39,17 @@ class CeilingTest extends TestCase public function testCELINGOpenOffice1Arg(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + self::setOpenOffice(); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=CEILING(5.1)'); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta(6, $result, 1E-12); } - public function testFLOORExcel1Arg(): void + public function testCEILINGExcel1Arg(): void { - $this->expectException(CalcExp::class); - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->mightHaveException('exception'); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=CEILING(5.1)'); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta(6, $result, 1E-12); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php index d5ada718..3a31b454 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CosTest extends TestCase +class CosTest extends AllSetupTeardown { /** * @dataProvider providerCos @@ -15,11 +11,8 @@ class CosTest extends TestCase */ public function testCos($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 2); $sheet->getCell('A1')->setValue("=COS($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php index 81dc9c75..83c9315c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CoshTest extends TestCase +class CoshTest extends AllSetupTeardown { /** * @dataProvider providerCosh @@ -15,11 +11,8 @@ class CoshTest extends TestCase */ public function testCosh($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 2); $sheet->getCell('A1')->setValue("=COSH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php index cb009a89..5ed9ac78 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CotTest extends TestCase +class CotTest extends AllSetupTeardown { /** * @dataProvider providerCOT @@ -16,11 +12,8 @@ class CotTest extends TestCase */ public function testCOT($expectedResult, $angle): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php index e4b42a4d..515ad0a8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CothTest extends TestCase +class CothTest extends AllSetupTeardown { /** * @dataProvider providerCOTH @@ -16,11 +12,8 @@ class CothTest extends TestCase */ public function testCOTH($expectedResult, $angle): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php index 8ae48cde..3b401ef2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CscTest extends TestCase +class CscTest extends AllSetupTeardown { /** * @dataProvider providerCSC @@ -16,11 +12,8 @@ class CscTest extends TestCase */ public function testCSC($expectedResult, $angle): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php index 4a7dbc05..7cf33099 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class CschTest extends TestCase +class CschTest extends AllSetupTeardown { /** * @dataProvider providerCSCH @@ -16,11 +12,8 @@ class CschTest extends TestCase */ public function testCSCH($expectedResult, $angle): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php index 080925b1..c8cc8645 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class EvenTest extends TestCase +class EvenTest extends AllSetupTeardown { /** * @dataProvider providerEVEN @@ -16,11 +12,8 @@ class EvenTest extends TestCase */ public function testEVEN($expectedResult, $value): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue("=EVEN($value)"); $sheet->getCell('A2')->setValue(3.7); self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php index f6092896..855e7605 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php @@ -2,31 +2,60 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class FactTest extends TestCase +class FactTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerFACT * * @param mixed $expectedResult - * @param $value + * @param mixed $arg1 */ - public function testFACT($expectedResult, $value): void + public function testFACT($expectedResult, $arg1): void { - $result = MathTrig::FACT($value); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=FACT()'); + } else { + $sheet->getCell('B1')->setValue('=FACT(A1)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); } public function providerFACT() { return require 'tests/data/Calculation/MathTrig/FACT.php'; } + + /** + * @dataProvider providerFACTGnumeric + * + * @param mixed $expectedResult + * @param mixed $arg1 + */ + public function testFACTGnumeric($expectedResult, $arg1): void + { + $this->mightHaveException($expectedResult); + self::setGnumeric(); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=FACT()'); + } else { + $sheet->getCell('B1')->setValue('=FACT(A1)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function providerFACTGnumeric() + { + return require 'tests/data/Calculation/MathTrig/FACTGNUMERIC.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php index ce546159..35ddd892 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class FloorMathTest extends TestCase +class FloorMathTest extends AllSetupTeardown { /** * @dataProvider providerFLOORMATH @@ -16,11 +12,8 @@ class FloorMathTest extends TestCase */ public function testFLOORMATH($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php index 961ca8ae..bf580134 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class FloorPreciseTest extends TestCase +class FloorPreciseTest extends AllSetupTeardown { /** * @dataProvider providerFLOORPRECISE @@ -16,11 +12,8 @@ class FloorPreciseTest extends TestCase */ public function testFLOORPRECISE($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php index 82a142c2..d684e84f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php @@ -2,26 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class FloorTest extends TestCase +class FloorTest extends AllSetupTeardown { - private $compatibilityMode; - - protected function setUp(): void - { - $this->compatibilityMode = Functions::getCompatibilityMode(); - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - - protected function tearDown(): void - { - Functions::setCompatibilityMode($this->compatibilityMode); - } - /** * @dataProvider providerFLOOR * @@ -30,11 +12,8 @@ class FloorTest extends TestCase */ public function testFLOOR($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); @@ -51,9 +30,8 @@ class FloorTest extends TestCase public function testFLOORGnumeric1Arg(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_GNUMERIC); - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + self::setGnumeric(); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=FLOOR(5.1)'); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta(5, $result, 1E-12); @@ -61,9 +39,8 @@ class FloorTest extends TestCase public function testFLOOROpenOffice1Arg(): void { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + self::setOpenOffice(); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=FLOOR(5.1)'); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta(5, $result, 1E-12); @@ -71,10 +48,8 @@ class FloorTest extends TestCase public function testFLOORExcel1Arg(): void { - $this->expectException(CalcExp::class); - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + $this->mightHaveException('exception'); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=FLOOR(5.1)'); $result = $sheet->getCell('A1')->getCalculatedValue(); self::assertEqualsWithDelta(5, $result, 1E-12); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php index 5c0b12c8..989b5bd1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class IntTest extends TestCase +class IntTest extends AllSetupTeardown { /** * @dataProvider providerINT @@ -16,11 +12,8 @@ class IntTest extends TestCase */ public function testINT($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php index 57b4a67f..55655d83 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class LcmTest extends TestCase +class LcmTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerLCM * @@ -20,7 +11,14 @@ class LcmTest extends TestCase */ public function testLCM($expectedResult, ...$args): void { - $result = MathTrig::LCM(...$args); + $sheet = $this->sheet; + $row = 0; + foreach ($args as $arg) { + ++$row; + $sheet->getCell("A$row")->setValue($arg); + } + $sheet->getCell('B1')->setValue("=LCM(A1:A$row)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php index a500c3f6..8831fe83 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php @@ -2,17 +2,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class MInverseTest extends TestCase +class MInverseTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerMINVERSE * @@ -28,4 +21,12 @@ class MInverseTest extends TestCase { return require 'tests/data/Calculation/MathTrig/MINVERSE.php'; } + + public function testOnSpreadsheet(): void + { + // very limited ability to test this in the absence of dynamic arrays + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue('=MINVERSE({1,2,3})'); // not square + self::assertSame('#VALUE!', $sheet->getCell('A1')->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php index 66fa80db..ca8ee5d7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php @@ -2,17 +2,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class MMultTest extends TestCase +class MMultTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerMMULT * @@ -28,4 +21,12 @@ class MMultTest extends TestCase { return require 'tests/data/Calculation/MathTrig/MMULT.php'; } + + public function testOnSpreadsheet(): void + { + // very limited ability to test this in the absence of dynamic arrays + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue('=MMULT({1,2,3}, {1,2,3})'); // incompatible dimensions + self::assertSame('#VALUE!', $sheet->getCell('A1')->getCalculatedValue()); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php index 87554d06..404193e9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class MRoundTest extends TestCase +class MRoundTest extends AllSetupTeardown { /** * @dataProvider providerMROUND @@ -16,11 +12,8 @@ class MRoundTest extends TestCase */ public function testMROUND($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php index 995ea2f3..b86a90c0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php @@ -2,25 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class MdeTermTest extends TestCase +class MdeTermTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerMDETERM * * @param mixed $expectedResult + * @param mixed $matrix expect a matrix */ - public function testMDETERM($expectedResult, ...$args): void + public function testMDETERM2($expectedResult, $matrix): void { - $result = MathTrig::MDETERM(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if (is_array($matrix)) { + $sheet->fromArray($matrix, null, 'A1', true); + $maxCol = $sheet->getHighestColumn(); + $maxRow = $sheet->getHighestRow(); + $sheet->getCell('Z1')->setValue("=MDETERM(A1:$maxCol$maxRow)"); + } else { + $sheet->getCell('Z1')->setValue("=MDETERM($matrix)"); + } + $result = $sheet->getCell('Z1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php index 45c558cd..5b3642ff 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php @@ -25,6 +25,7 @@ class MovedFunctionsTest extends TestCase self::assertEqualsWithDelta(0, MathTrig::builtinATAN(0), 1E-9); self::assertEqualsWithDelta(0, MathTrig::builtinATANH(0), 1E-9); self::assertEqualsWithDelta('#DIV/0!', MathTrig::ATAN2(0, 0), 1E-9); + self::assertEquals('12', MathTrig::BASE(10, 8)); self::assertEquals(-6, MathTrig::CEILING(-4.5, -2)); self::assertEquals(1, MathTrig::builtinCOS(0)); self::assertEquals(1, MathTrig::builtinCOSH(0)); @@ -33,20 +34,40 @@ class MovedFunctionsTest extends TestCase self::assertEquals('#DIV/0!', MathTrig::CSC(0)); self::assertEquals('#DIV/0!', MathTrig::CSCH(0)); self::assertEquals(6, MathTrig::EVEN(4.5)); + self::assertEquals(6, MathTrig::FACT(3)); self::assertEquals(-6, MathTrig::FLOOR(-4.5, 2)); self::assertEquals(0.23, MathTrig::FLOORMATH(0.234, 0.01)); self::assertEquals(-4, MathTrig::FLOORPRECISE(-2.5, 2)); self::assertEquals(-9, MathTrig::INT(-8.3)); + self::assertEquals(12, MathTrig::LCM(4, 6)); + self::assertEquals(1, MathTrig::MDETERM([1])); + self::assertEquals( + [[2, 2], [2, 1]], + MathTrig::MINVERSE([[-0.5, 1.0], [1.0, -1.0]]) + ); + self::assertEquals( + [[23], [53]], + MathTrig::MMULT([[1, 2], [3, 4]], [[7], [8]]) + ); self::assertEquals(6, MathTrig::MROUND(7.3, 3)); + self::assertEquals(1, MathTrig::MULTINOMIAL(1)); self::assertEquals(5, MathTrig::ODD(4.5)); + self::assertEquals(8, MathTrig::PRODUCT(1, 2, 4)); + self::assertEquals(8, MathTrig::QUOTIENT(17, 2)); + self::assertEquals('I', MathTrig::ROMAN(1)); self::assertEquals(3.3, MathTrig::builtinROUND(3.27, 1)); self::assertEquals(662, MathTrig::ROUNDDOWN(662.79, 0)); self::assertEquals(663, MathTrig::ROUNDUP(662.79, 0)); self::assertEquals(1, MathTrig::SEC(0)); self::assertEquals(1, MathTrig::SECH(0)); + self::assertEquals(3780, MathTrig::SERIESSUM(5, 1, 1, [1, 1, 0, 1, 1])); self::assertEquals(1, MathTrig::SIGN(79.2)); self::assertEquals(0, MathTrig::builtinSIN(0)); self::assertEquals(0, MathTrig::builtinSINH(0)); + self::assertEquals(0, MathTrig::SUBTOTAL(2, [0, 0])); + self::assertEquals(7, MathTrig::SUM(1, 2, 4)); + self::assertEquals(4, MathTrig::SUMIF([[2], [4]], '>2')); + self::assertEquals(17, MathTrig::SUMPRODUCT([1, 2, 3], [5, 0, 4])); self::assertEquals(0, MathTrig::builtinTAN(0)); self::assertEquals(0, MathTrig::builtinTANH(0)); self::assertEquals(70, MathTrig::TRUNC(79.2, -1)); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php index 93735ba9..1c22cc40 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class MultinomialTest extends TestCase +class MultinomialTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerMULTINOMIAL * @@ -20,7 +11,19 @@ class MultinomialTest extends TestCase */ public function testMULTINOMIAL($expectedResult, ...$args): void { - $result = MathTrig::MULTINOMIAL(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $row = 0; + $excelArg = ''; + foreach ($args as $arg) { + ++$row; + $excelArg = "A1:A$row"; + if ($arg !== null) { + $sheet->getCell("A$row")->setValue($arg); + } + } + $sheet->getCell('B1')->setValue("=MULTINOMIAL($excelArg)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php index ed262d9c..c599a30e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class OddTest extends TestCase +class OddTest extends AllSetupTeardown { /** * @dataProvider providerODD @@ -16,11 +12,8 @@ class OddTest extends TestCase */ public function testODD($expectedResult, $value): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->getCell('A1')->setValue("=ODD($value)"); $sheet->getCell('A2')->setValue(3.7); self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php index 251b783b..c38eb130 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class ProductTest extends TestCase +class ProductTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerPRODUCT * @@ -20,7 +11,14 @@ class ProductTest extends TestCase */ public function testPRODUCT($expectedResult, ...$args): void { - $result = MathTrig::PRODUCT(...$args); + $sheet = $this->sheet; + $row = 0; + foreach ($args as $arg) { + ++$row; + $sheet->getCell("A$row")->setValue($arg); + } + $sheet->getCell('B1')->setValue("=PRODUCT(A1:A$row)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php index 4232729a..3df2ed99 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php @@ -2,26 +2,34 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class QuotientTest extends TestCase +class QuotientTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerQUOTIENT * * @param mixed $expectedResult + * @param mixed $arg1 + * @param mixed $arg2 */ - public function testQUOTIENT($expectedResult, ...$args): void + public function testQUOTIENT($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted'): void { - $result = MathTrig::QUOTIENT(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('A1')->setValue($arg1); + } + if ($arg2 !== null) { + $sheet->getCell('A2')->setValue($arg2); + } + if ($arg1 === 'omitted') { + $sheet->getCell('B1')->setValue('=QUOTIENT()'); + } elseif ($arg2 === 'omitted') { + $sheet->getCell('B1')->setValue('=QUOTIENT(A1)'); + } else { + $sheet->getCell('B1')->setValue('=QUOTIENT(A1, A2)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertSame($expectedResult, $result); } public function providerQUOTIENT() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php index e913e5d7..0d71ece0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class RomanTest extends TestCase +class RomanTest extends AllSetupTeardown { /** * @dataProvider providerROMAN @@ -16,11 +12,8 @@ class RomanTest extends TestCase */ public function testROMAN($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A3', 49); $sheet->getCell('A1')->setValue("=ROMAN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); @@ -31,11 +24,4 @@ class RomanTest extends TestCase { return require 'tests/data/Calculation/MathTrig/ROMAN.php'; } - - // Confirm that deprecated stub left in MathTrig works. - // Delete this test when stub is finally deleted. - public function testDeprecated(): void - { - self::assertEquals('I', \PhpOffice\PhpSpreadsheet\Calculation\MathTrig::ROMAN(1)); - } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php index 1ea1f7cb..e450c29e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class RoundDownTest extends TestCase +class RoundDownTest extends AllSetupTeardown { /** * @dataProvider providerRoundDown @@ -16,11 +12,8 @@ class RoundDownTest extends TestCase */ public function testRoundDown($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php index dd09bbaa..ee52b93d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class RoundTest extends TestCase +class RoundTest extends AllSetupTeardown { /** * @dataProvider providerRound @@ -16,11 +12,8 @@ class RoundTest extends TestCase */ public function testRound($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php index 7907be42..6aa6c796 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class RoundUpTest extends TestCase +class RoundUpTest extends AllSetupTeardown { /** * @dataProvider providerRoundUp @@ -16,11 +12,8 @@ class RoundUpTest extends TestCase */ public function testRoundUp($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php index a47ae7b5..6a008102 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class SecTest extends TestCase +class SecTest extends AllSetupTeardown { /** * @dataProvider providerSEC @@ -16,11 +12,8 @@ class SecTest extends TestCase */ public function testSEC($expectedResult, $angle): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php index 65ed7b73..a93f37c5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class SechTest extends TestCase +class SechTest extends AllSetupTeardown { /** * @dataProvider providerSECH @@ -16,11 +12,8 @@ class SechTest extends TestCase */ public function testSECH($expectedResult, $angle): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php index 689336a3..86a40d07 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php @@ -3,24 +3,39 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class SeriesSumTest extends TestCase +class SeriesSumTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSERIESSUM * * @param mixed $expectedResult + * @param mixed $arg1 + * @param mixed $arg2 + * @param mixed $arg3 */ - public function testSERIESSUM($expectedResult, ...$args): void + public function testSERIESSUM($expectedResult, $arg1, $arg2, $arg3, ...$args): void { - $result = MathTrig::SERIESSUM(...$args); + $sheet = $this->sheet; + if ($arg1 !== null) { + $sheet->getCell('C1')->setValue($arg1); + } + if ($arg2 !== null) { + $sheet->getCell('C2')->setValue($arg2); + } + if ($arg3 !== null) { + $sheet->getCell('C3')->setValue($arg3); + } + $row = 0; + $aArgs = Functions::flattenArray($args); + foreach ($aArgs as $arg) { + ++$row; + if ($arg !== null) { + $sheet->getCell("A$row")->setValue($arg); + } + } + $sheet->getCell('B1')->setValue("=SERIESSUM(C1, C2, C3, A1:A$row)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php index a4311219..dff5370d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class SignTest extends TestCase +class SignTest extends AllSetupTeardown { /** * @dataProvider providerSIGN @@ -16,11 +12,8 @@ class SignTest extends TestCase */ public function testSIGN($expectedResult, $value): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 0); $sheet->setCellValue('A4', -3.8); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php index e9ad6329..c460605f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class SinTest extends TestCase +class SinTest extends AllSetupTeardown { /** * @dataProvider providerSin @@ -15,11 +11,8 @@ class SinTest extends TestCase */ public function testSin($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 2); $sheet->getCell('A1')->setValue("=SIN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php index 38bfc7ef..30c40615 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class SinhTest extends TestCase +class SinhTest extends AllSetupTeardown { /** * @dataProvider providerCosh @@ -15,11 +11,8 @@ class SinhTest extends TestCase */ public function testSinh($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 2); $sheet->getCell('A1')->setValue("=SINH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php index a629a7f4..7d44c551 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php @@ -2,53 +2,23 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PhpOffice\PhpSpreadsheet\Cell\Cell; -use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension; -use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension; -use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; -use PHPUnit\Framework\TestCase; - -class SubTotalTest extends TestCase +class SubTotalTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUBTOTAL * * @param mixed $expectedResult + * @param mixed $type expect an integer */ - public function testSUBTOTAL($expectedResult, ...$args): void + public function testSubtotal($expectedResult, $type): void { - $cell = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getValue', 'isFormula']) - ->disableOriginalConstructor() - ->getMock(); - $cell->method('getValue') - ->willReturn(null); - $cell->method('getValue') - ->willReturn(false); - $worksheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['cellExists', 'getCell']) - ->disableOriginalConstructor() - ->getMock(); - $worksheet->method('cellExists') - ->willReturn(true); - $worksheet->method('getCell') - ->willReturn($cell); - $cellReference = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getWorksheet']) - ->disableOriginalConstructor() - ->getMock(); - $cellReference->method('getWorksheet') - ->willReturn($worksheet); - - array_push($args, $cellReference); - $result = MathTrig::SUBTOTAL(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->fromArray([[0], [1], [1], [2], [3], [5], [8], [13], [21], [34], [55], [89]], null, 'A1', true); + $maxCol = $sheet->getHighestColumn(); + $maxRow = $sheet->getHighestRow(); + $sheet->getCell('D2')->setValue("=SUBTOTAL($type, A1:$maxCol$maxRow)"); + $result = $sheet->getCell('D2')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } @@ -57,142 +27,102 @@ class SubTotalTest extends TestCase return require 'tests/data/Calculation/MathTrig/SUBTOTAL.php'; } - protected function rowVisibility($data) - { - foreach ($data as $row => $visibility) { - yield $row => $visibility; - } - } - /** - * @dataProvider providerHiddenSUBTOTAL + * @dataProvider providerSUBTOTAL * * @param mixed $expectedResult - * @param mixed $hiddenRows + * @param mixed $type expect an integer */ - public function testHiddenSUBTOTAL($expectedResult, $hiddenRows, ...$args): void + public function testSubtotalColumnHidden($expectedResult, $type): void { - $visibilityGenerator = $this->rowVisibility($hiddenRows); - - $rowDimension = $this->getMockBuilder(RowDimension::class) - ->onlyMethods(['getVisible']) - ->disableOriginalConstructor() - ->getMock(); - $rowDimension->method('getVisible') - ->willReturnCallback(function () use ($visibilityGenerator) { - $result = $visibilityGenerator->current(); - $visibilityGenerator->next(); - - return $result; - }); - $columnDimension = $this->getMockBuilder(ColumnDimension::class) - ->onlyMethods(['getVisible']) - ->disableOriginalConstructor() - ->getMock(); - $columnDimension->method('getVisible') - ->willReturn(true); - $cell = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getValue', 'isFormula']) - ->disableOriginalConstructor() - ->getMock(); - $cell->method('getValue') - ->willReturn(''); - $cell->method('getValue') - ->willReturn(false); - $worksheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['cellExists', 'getCell', 'getRowDimension', 'getColumnDimension']) - ->disableOriginalConstructor() - ->getMock(); - $worksheet->method('cellExists') - ->willReturn(true); - $worksheet->method('getCell') - ->willReturn($cell); - $worksheet->method('getRowDimension') - ->willReturn($rowDimension); - $worksheet->method('getColumnDimension') - ->willReturn($columnDimension); - $cellReference = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getWorksheet']) - ->disableOriginalConstructor() - ->getMock(); - $cellReference->method('getWorksheet') - ->willReturn($worksheet); - - array_push($args, $cellReference); - $result = MathTrig::SUBTOTAL(...$args); + // Hidden columns don't affect calculation, only hidden rows + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->fromArray([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89], null, 'A1', true); + $maxCol = $sheet->getHighestColumn(); + $maxRow = $sheet->getHighestRow(); + $hiddenColumns = [ + 'A' => false, + 'B' => true, + 'C' => false, + 'D' => true, + 'E' => false, + 'F' => false, + 'G' => false, + 'H' => true, + 'I' => false, + 'J' => true, + 'K' => true, + 'L' => false, + ]; + foreach ($hiddenColumns as $col => $hidden) { + $sheet->getColumnDimension($col)->setVisible($hidden); + } + $sheet->getCell('D2')->setValue("=SUBTOTAL($type, A1:$maxCol$maxRow)"); + $result = $sheet->getCell('D2')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerHiddenSUBTOTAL() + /** + * @dataProvider providerSUBTOTALHIDDEN + * + * @param mixed $expectedResult + * @param mixed $type expect an integer + */ + public function testSubtotalRowHidden($expectedResult, $type): void + { + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->fromArray([[0], [1], [1], [2], [3], [5], [8], [13], [21], [34], [55], [89]], null, 'A1', true); + $maxCol = $sheet->getHighestColumn(); + $maxRow = $sheet->getHighestRow(); + $visibleRows = [ + '1' => false, + '2' => true, + '3' => false, + '4' => true, + '5' => false, + '6' => false, + '7' => false, + '8' => true, + '9' => false, + '10' => true, + '11' => true, + '12' => false, + ]; + foreach ($visibleRows as $row => $visible) { + $sheet->getRowDimension($row)->setVisible($visible); + } + $sheet->getCell('D2')->setValue("=SUBTOTAL($type, A1:$maxCol$maxRow)"); + $result = $sheet->getCell('D2')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerSUBTOTALHIDDEN() { return require 'tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php'; } - protected function cellValues(array $cellValues) + public function testSubtotalNested(): void { - foreach ($cellValues as $k => $v) { - yield $k => $v; - } - } - - protected function cellIsFormula(array $cellValues) - { - foreach ($cellValues as $cellValue) { - yield is_string($cellValue) && $cellValue[0] === '='; - } - } - - /** - * @dataProvider providerNestedSUBTOTAL - * - * @param mixed $expectedResult - */ - public function testNestedSUBTOTAL($expectedResult, ...$args): void - { - $cellValueGenerator = $this->cellValues(Functions::flattenArray(array_slice($args, 1))); - $cellIsFormulaGenerator = $this->cellIsFormula(Functions::flattenArray(array_slice($args, 1))); - - $cell = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getValue', 'isFormula']) - ->disableOriginalConstructor() - ->getMock(); - $cell->method('getValue') - ->willReturnCallback(function () use ($cellValueGenerator) { - $result = $cellValueGenerator->current(); - $cellValueGenerator->next(); - - return $result; - }); - $cell->method('isFormula') - ->willReturnCallback(function () use ($cellIsFormulaGenerator) { - $result = $cellIsFormulaGenerator->current(); - $cellIsFormulaGenerator->next(); - - return $result; - }); - $worksheet = $this->getMockBuilder(Worksheet::class) - ->onlyMethods(['cellExists', 'getCell']) - ->disableOriginalConstructor() - ->getMock(); - $worksheet->method('cellExists') - ->willReturn(true); - $worksheet->method('getCell') - ->willReturn($cell); - $cellReference = $this->getMockBuilder(Cell::class) - ->onlyMethods(['getWorksheet']) - ->disableOriginalConstructor() - ->getMock(); - $cellReference->method('getWorksheet') - ->willReturn($worksheet); - - array_push($args, $cellReference); - - $result = MathTrig::SUBTOTAL(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); - } - - public function providerNestedSUBTOTAL() - { - return require 'tests/data/Calculation/MathTrig/SUBTOTALNESTED.php'; + $sheet = $this->sheet; + $sheet->fromArray( + [ + [123], + [234], + ['=SUBTOTAL(1,A1:A2)'], + ['=ROMAN(SUBTOTAL(1, A1:A2))'], + ['This is text containing "=" and "SUBTOTAL("'], + ['=AGGREGATE(1, 0, A1:A2)'], + ['=SUM(2, 3)'], + ], + null, + 'A1', + true + ); + $maxCol = $sheet->getHighestColumn(); + $maxRow = $sheet->getHighestRow(); + $sheet->getCell('H1')->setValue("=SUBTOTAL(9, A1:$maxCol$maxRow)"); + self::assertEquals(362, $sheet->getCell('H1')->getCalculatedValue()); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php index f7ff928f..7bcd274e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php @@ -2,25 +2,36 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class SumIfTest extends TestCase +class SumIfTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMIF * * @param mixed $expectedResult + * @param mixed $condition */ - public function testSUMIF($expectedResult, ...$args): void + public function testSUMIF2($expectedResult, array $array1, $condition, ?array $array2 = null): void { - $result = MathTrig::SUMIF(...$args); + $this->mightHaveException($expectedResult); + if ($expectedResult === 'incomplete') { + self::markTestIncomplete('Raises formula error - researching solution'); + } + $sheet = $this->sheet; + $sheet->fromArray($array1, null, 'A1', true); + $maxARow = count($array1); + $firstArg = "A1:A$maxARow"; + //$secondArg = is_string($condition) ? "\"$condition\"" : $condition; + $sheet->getCell('B1')->setValue($condition); + $secondArg = 'B1'; + if (empty($array2)) { + $sheet->getCell('D1')->setValue("=SUMIF($firstArg, $secondArg)"); + } else { + $sheet->fromArray($array2, null, 'C1', true); + $maxCRow = count($array2); + $thirdArg = "C1:C$maxCRow"; + $sheet->getCell('D1')->setValue("=SUMIF($firstArg, $secondArg, $thirdArg)"); + } + $result = $sheet->getCell('D1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php index b34036e5..6e7f49e8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php @@ -3,16 +3,9 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class SumProductTest extends TestCase +class SumProductTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMPRODUCT * @@ -20,7 +13,24 @@ class SumProductTest extends TestCase */ public function testSUMPRODUCT($expectedResult, ...$args): void { - $result = MathTrig::SUMPRODUCT(...$args); + $sheet = $this->sheet; + $row = 0; + $arrayArg = ''; + foreach ($args as $arr) { + $arr2 = Functions::flattenArray($arr); + $startRow = 0; + foreach ($arr2 as $arr3) { + ++$row; + if (!$startRow) { + $startRow = $row; + } + $sheet->getCell("A$row")->setValue($arr3); + } + $arrayArg .= "A$startRow:A$row,"; + } + $arrayArg = substr($arrayArg, 0, -1); // strip trailing comma + $sheet->getCell('B1')->setValue("=SUMPRODUCT($arrayArg)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php new file mode 100644 index 00000000..5bd03318 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php @@ -0,0 +1,29 @@ +sheet; + $row = 0; + foreach ($args as $arg) { + ++$row; + $sheet->getCell("A$row")->setValue($arg); + } + $sheet->getCell('B1')->setValue("=SUM(A1:A$row)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerSUM() + { + return require 'tests/data/Calculation/MathTrig/SUM.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php index 5a482cd8..4db9dbb9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class TanTest extends TestCase +class TanTest extends AllSetupTeardown { /** * @dataProvider providerTan @@ -15,11 +11,8 @@ class TanTest extends TestCase */ public function testTan($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1); $sheet->getCell('A1')->setValue("=TAN($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php index 5fe50d7c..68f87cd2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class TanhTest extends TestCase +class TanhTest extends AllSetupTeardown { /** * @dataProvider providerTanh @@ -15,11 +11,8 @@ class TanhTest extends TestCase */ public function testTanh($expectedResult, string $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1); $sheet->getCell('A1')->setValue("=TANH($formula)"); $result = $sheet->getCell('A1')->getCalculatedValue(); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php index 37740c0d..e4127e57 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php @@ -2,11 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class TruncTest extends TestCase +class TruncTest extends AllSetupTeardown { /** * @dataProvider providerTRUNC @@ -16,11 +12,8 @@ class TruncTest extends TestCase */ public function testTRUNC($expectedResult, $formula): void { - if ($expectedResult === 'exception') { - $this->expectException(CalcExp::class); - } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; $sheet->setCellValue('A2', 1.3); $sheet->setCellValue('A3', 2.7); $sheet->setCellValue('A4', -3.8); diff --git a/tests/data/Calculation/MathTrig/BASE.php b/tests/data/Calculation/MathTrig/BASE.php index c2802dd9..1f67fe2a 100644 --- a/tests/data/Calculation/MathTrig/BASE.php +++ b/tests/data/Calculation/MathTrig/BASE.php @@ -56,4 +56,10 @@ return [ 15, -1, ], + ['#VALUE!', 15, -1, '"X"'], + ['#NUM!', 15, 37], // radix > 36 + ['#NUM!', 2 ** 54, 16], // number > 2 ** 53 + ['00000120', 15, 3, 8.1], + ['exception'], + ['exception', 1], ]; diff --git a/tests/data/Calculation/MathTrig/FACT.php b/tests/data/Calculation/MathTrig/FACT.php index 331e402d..c789ced8 100644 --- a/tests/data/Calculation/MathTrig/FACT.php +++ b/tests/data/Calculation/MathTrig/FACT.php @@ -7,7 +7,7 @@ return [ ], [ 1, - 1.8999999999999999, + 1.9, ], [ 1, @@ -35,7 +35,7 @@ return [ ], [ 6, - 3.2000000000000002, + 3.2, ], [ '#VALUE!', diff --git a/tests/data/Calculation/MathTrig/FACTGNUMERIC.php b/tests/data/Calculation/MathTrig/FACTGNUMERIC.php new file mode 100644 index 00000000..0f040dd0 --- /dev/null +++ b/tests/data/Calculation/MathTrig/FACTGNUMERIC.php @@ -0,0 +1,44 @@ + ['A' => 0], - 2 => ['A' => 1], - 3 => ['A' => 1], - 4 => ['A' => 2], - 5 => ['A' => 3], - 6 => ['A' => 5], - 7 => ['A' => 8], - 8 => ['A' => 13], - 9 => ['A' => 21], - 10 => ['A' => 34], - 11 => ['A' => 55], - 12 => ['A' => 89], -]; - return [ - [ - 19.3333333333333, - 1, - $baseTestData, - ], - [ - 12, - 2, - $baseTestData, - ], - [ - 12, - 3, - $baseTestData, - ], - [ - 89, - 4, - $baseTestData, - ], - [ - 0, - 5, - $baseTestData, - ], - [ - 0, - 6, - $baseTestData, - ], - [ - 27.5196899207337, - 7, - $baseTestData, - ], - [ - 26.3480971271593, - 8, - $baseTestData, - ], - [ - 232, - 9, - $baseTestData, - ], - [ - 757.3333333333330, - 10, - $baseTestData, - ], - [ - 694.2222222222220, - 11, - $baseTestData, - ], + [19.3333333333333, 1], + [12, 2], + [12, 3], + [89, 4], + [0, 5], + [0, 6], + [27.5196899207337, 7], + [26.3480971271593, 8], + [232, 9], + [757.3333333333330, '10'], + [694.2222222222220, 11.1], + ['#VALUE!', 0], + ['#VALUE!', -1], + ['#VALUE!', 12], + ['#VALUE!', '"X"'], ]; diff --git a/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php b/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php index accaf03e..df6375dc 100644 --- a/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php +++ b/tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php @@ -1,100 +1,15 @@ ['A' => 0], - 2 => ['A' => 1], - 3 => ['A' => 1], - 4 => ['A' => 2], - 5 => ['A' => 3], - 6 => ['A' => 5], - 7 => ['A' => 8], - 8 => ['A' => 13], - 9 => ['A' => 21], - 10 => ['A' => 34], - 11 => ['A' => 55], - 12 => ['A' => 89], -]; - -$hiddenRows = [ - 1 => false, - 2 => true, - 3 => false, - 4 => true, - 5 => false, - 6 => false, - 7 => false, - 8 => true, - 9 => false, - 10 => true, - 11 => true, - 12 => false, -]; - return [ - [ - 21, - $hiddenRows, - 101, - $baseTestData, - ], - [ - 5, - $hiddenRows, - 102, - $baseTestData, - ], - [ - 5, - $hiddenRows, - 103, - $baseTestData, - ], - [ - 55, - $hiddenRows, - 104, - $baseTestData, - ], - [ - 1, - $hiddenRows, - 105, - $baseTestData, - ], - [ - 48620, - $hiddenRows, - 106, - $baseTestData, - ], - [ - 23.1840462387393, - $hiddenRows, - 107, - $baseTestData, - ], - [ - 20.7364413533277, - $hiddenRows, - 108, - $baseTestData, - ], - [ - 105, - $hiddenRows, - 109, - $baseTestData, - ], - [ - 537.5, - $hiddenRows, - 110, - $baseTestData, - ], - [ - 430, - $hiddenRows, - 111, - $baseTestData, - ], + [21, 101], + [5, 102], + [5, 103], + [55, 104], + [1, 105], + [48620, 106], + [23.1840462387393, 107], + [20.7364413533277, 108], + [105, 109], + [537.5, 110], + [430, 111], ]; diff --git a/tests/data/Calculation/MathTrig/SUBTOTALNESTED.php b/tests/data/Calculation/MathTrig/SUBTOTALNESTED.php deleted file mode 100644 index e1ae38f8..00000000 --- a/tests/data/Calculation/MathTrig/SUBTOTALNESTED.php +++ /dev/null @@ -1,18 +0,0 @@ - ['A' => 123], - 2 => ['A' => 234], - 3 => ['A' => '=SUBTOTAL(1, A1:A2)'], - 4 => ['A' => '=ROMAN(SUBTOTAL(1, A1:A2))'], - 5 => ['A' => 'This is text containing "=" and "SUBTOTAL("'], - 6 => ['A' => '=AGGREGATE(1, A1:A2)'], -]; - -return [ - [ - 357, - 9, - $baseTestData, - ], -]; diff --git a/tests/data/Calculation/MathTrig/SUM.php b/tests/data/Calculation/MathTrig/SUM.php new file mode 100644 index 00000000..a8219076 --- /dev/null +++ b/tests/data/Calculation/MathTrig/SUM.php @@ -0,0 +1,8 @@ + Date: Fri, 26 Mar 2021 18:29:05 +0100 Subject: [PATCH 136/187] Switch calls to deprecated function methods to the equivalent new methods (#1957) --- .../Calculation/Database/DProduct.php | 2 +- .../Calculation/Database/DSum.php | 2 +- .../Calculation/Financial/Amortization.php | 10 ++-- .../Calculation/Financial/Coupons.php | 23 ++++----- .../Calculation/Financial/Helpers.php | 4 +- .../Financial/Securities/BaseValidations.php | 4 +- .../Financial/Securities/Price.php | 12 ++--- .../Financial/Securities/Yields.php | 14 +++--- .../Calculation/Financial/TreasuryBill.php | 49 +++++++++---------- .../Calculation/MathTrig/Fact.php | 2 +- .../Calculation/Statistical.php | 2 +- .../Statistical/Distributions/Poisson.php | 4 +- .../Calculation/Statistical/Permutations.php | 2 +- .../Calculation/TextData/Format.php | 8 +-- .../Calculation/TextData/Replace.php | 3 +- src/PhpSpreadsheet/Shared/Date.php | 19 +++---- src/PhpSpreadsheet/Worksheet/AutoFilter.php | 4 +- 17 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Database/DProduct.php b/src/PhpSpreadsheet/Calculation/Database/DProduct.php index 107c69c0..f02eb196 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DProduct.php +++ b/src/PhpSpreadsheet/Calculation/Database/DProduct.php @@ -38,7 +38,7 @@ class DProduct extends DatabaseAbstract return null; } - return MathTrig::PRODUCT( + return MathTrig\Product::funcProduct( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Database/DSum.php b/src/PhpSpreadsheet/Calculation/Database/DSum.php index 473bacd1..4f784e19 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DSum.php +++ b/src/PhpSpreadsheet/Calculation/Database/DSum.php @@ -38,7 +38,7 @@ class DSum extends DatabaseAbstract return null; } - return MathTrig::SUM( + return MathTrig\Sum::funcSum( self::getFilteredColumn($database, $field, $criteria) ); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php index 7bb7fb40..f1a9e3f5 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Amortization @@ -47,7 +47,7 @@ class Amortization $rate = Functions::flattenSingleValue($rate); $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); - $yearFrac = DateTime::YEARFRAC($purchased, $firstPeriod, $basis); + $yearFrac = DateTimeExcel\YearFrac::funcYearFrac($purchased, $firstPeriod, $basis); if (is_string($yearFrac)) { return $yearFrac; } @@ -116,13 +116,13 @@ class Amortization $fOneRate = $cost * $rate; $fCostDelta = $cost - $salvage; // Note, quirky variation for leap years on the YEARFRAC for this function - $purchasedYear = DateTime::YEAR($purchased); - $yearFrac = DateTime::YEARFRAC($purchased, $firstPeriod, $basis); + $purchasedYear = DateTimeExcel\Year::funcYear($purchased); + $yearFrac = DateTimeExcel\YearFrac::funcYearFrac($purchased, $firstPeriod, $basis); if (is_string($yearFrac)) { return $yearFrac; } - if (($basis == 1) && ($yearFrac < 1) && (DateTime::isLeapYear($purchasedYear))) { + if (($basis == 1) && ($yearFrac < 1) && (DateTimeExcel\Helpers::isLeapYear($purchasedYear))) { $yearFrac *= 365 / 366; } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php index d0efd689..c4a60d90 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -2,7 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date; @@ -60,14 +61,14 @@ class Coupons return $e->getMessage(); } - $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); if ($basis === Helpers::DAYS_PER_YEAR_ACTUAL) { - return abs(DateTime::DAYS($prev, $settlement)); + return abs(DateTimeExcel\Days::funcDays($prev, $settlement)); } - return DateTime::YEARFRAC($prev, $settlement, $basis) * $daysPerYear; + return DateTimeExcel\YearFrac::funcYearFrac($prev, $settlement, $basis) * $daysPerYear; } /** @@ -121,7 +122,7 @@ class Coupons case Helpers::DAYS_PER_YEAR_ACTUAL: // Actual/actual if ($frequency == self::FREQUENCY_ANNUAL) { - $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); return $daysPerYear / $frequency; } @@ -179,7 +180,7 @@ class Coupons return $e->getMessage(); } - $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT); if ($basis === Helpers::DAYS_PER_YEAR_NASD) { @@ -190,7 +191,7 @@ class Coupons } } - return DateTime::YEARFRAC($settlement, $next, $basis) * $daysPerYear; + return DateTimeExcel\YearFrac::funcYearFrac($settlement, $next, $basis) * $daysPerYear; } /** @@ -286,7 +287,7 @@ class Coupons return $e->getMessage(); } - $yearsBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, 0); + $yearsBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, 0); return ceil($yearsBetweenSettlementAndMaturity * $frequency); } @@ -344,11 +345,11 @@ class Coupons * * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month * - * @param \DateTime $testDate The date for testing + * @param DateTime $testDate The date for testing * * @return bool */ - private static function isLastDayOfMonth(\DateTime $testDate) + private static function isLastDayOfMonth(DateTime $testDate) { return $testDate->format('d') === $testDate->format('t'); } @@ -376,7 +377,7 @@ class Coupons private static function validateInputDate($date) { - $date = DateTime::getDateValue($date); + $date = DateTimeExcel\Helpers::getDateValue($date); if (is_string($date)) { throw new Exception(Functions::VALUE()); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Helpers.php b/src/PhpSpreadsheet/Calculation/Financial/Helpers.php index 0b8d97b1..08c942ab 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Helpers.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Helpers @@ -42,7 +42,7 @@ class Helpers case self::DAYS_PER_YEAR_365: return 365; case self::DAYS_PER_YEAR_ACTUAL: - return (DateTime::isLeapYear($year)) ? 366 : 365; + return (DateTimeExcel\Helpers::isLeapYear($year)) ? 366 : 365; } return Functions::NAN(); diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php index 88cb8660..2a5e5dd2 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants as SecuritiesConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -11,7 +11,7 @@ abstract class BaseValidations { protected static function validateInputDate($date) { - $date = DateTime::getDateValue($date); + $date = DateTimeExcel\Helpers::getDateValue($date); if (is_string($date)) { throw new Exception(Functions::VALUE()); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php index 14be7f84..18a0a2e1 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Coupons; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers; @@ -117,7 +117,7 @@ class Price extends BaseValidations return $e->getMessage(); } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; @@ -169,23 +169,23 @@ class Price extends BaseValidations return $e->getMessage(); } - $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); if (!is_numeric($daysPerYear)) { return $daysPerYear; } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + $daysBetweenIssueAndSettlement = DateTimeExcel\YearFrac::funcYearFrac($issue, $settlement, $basis); if (!is_numeric($daysBetweenIssueAndSettlement)) { // return date error return $daysBetweenIssueAndSettlement; } $daysBetweenIssueAndSettlement *= $daysPerYear; - $daysBetweenIssueAndMaturity = DateTime::YEARFRAC($issue, $maturity, $basis); + $daysBetweenIssueAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($issue, $maturity, $basis); if (!is_numeric($daysBetweenIssueAndMaturity)) { // return date error return $daysBetweenIssueAndMaturity; } $daysBetweenIssueAndMaturity *= $daysPerYear; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php index 0918d637..86151904 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -49,11 +49,11 @@ class Yields extends BaseValidations return $e->getMessage(); } - $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); if (!is_numeric($daysPerYear)) { return $daysPerYear; } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; @@ -106,23 +106,23 @@ class Yields extends BaseValidations return $e->getMessage(); } - $daysPerYear = Helpers::daysPerYear(DateTime::YEAR($settlement), $basis); + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); if (!is_numeric($daysPerYear)) { return $daysPerYear; } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + $daysBetweenIssueAndSettlement = DateTimeExcel\YearFrac::funcYearFrac($issue, $settlement, $basis); if (!is_numeric($daysBetweenIssueAndSettlement)) { // return date error return $daysBetweenIssueAndSettlement; } $daysBetweenIssueAndSettlement *= $daysPerYear; - $daysBetweenIssueAndMaturity = DateTime::YEARFRAC($issue, $maturity, $basis); + $daysBetweenIssueAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($issue, $maturity, $basis); if (!is_numeric($daysBetweenIssueAndMaturity)) { // return date error return $daysBetweenIssueAndMaturity; } $daysBetweenIssueAndMaturity *= $daysPerYear; - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; diff --git a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php index 3177124a..966500bf 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php +++ b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php @@ -2,7 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class TreasuryBill @@ -27,11 +28,11 @@ class TreasuryBill $maturity = Functions::flattenSingleValue($maturity); $discount = Functions::flattenSingleValue($discount); - if ( - is_string($maturity = DateTime::getDateValue($maturity)) || - is_string($settlement = DateTime::getDateValue($settlement)) - ) { - return Functions::VALUE(); + try { + $maturity = DateTimeExcel\Helpers::getDateValue($maturity); + $settlement = DateTimeExcel\Helpers::getDateValue($settlement); + } catch (Exception $e) { + return $e->getMessage(); } // Validate @@ -41,11 +42,9 @@ class TreasuryBill } $daysBetweenSettlementAndMaturity = $maturity - $settlement; + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($maturity), Helpers::DAYS_PER_YEAR_ACTUAL); - if ( - $daysBetweenSettlementAndMaturity > Helpers::daysPerYear(DateTime::YEAR($maturity), Helpers::DAYS_PER_YEAR_ACTUAL) || - $daysBetweenSettlementAndMaturity < 0 - ) { + if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { return Functions::NAN(); } @@ -75,11 +74,11 @@ class TreasuryBill $maturity = Functions::flattenSingleValue($maturity); $discount = Functions::flattenSingleValue($discount); - if ( - is_string($maturity = DateTime::getDateValue($maturity)) || - is_string($settlement = DateTime::getDateValue($settlement)) - ) { - return Functions::VALUE(); + try { + $maturity = DateTimeExcel\Helpers::getDateValue($maturity); + $settlement = DateTimeExcel\Helpers::getDateValue($settlement); + } catch (Exception $e) { + return $e->getMessage(); } // Validate @@ -89,13 +88,12 @@ class TreasuryBill } $daysBetweenSettlementAndMaturity = $maturity - $settlement; + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($maturity), Helpers::DAYS_PER_YEAR_ACTUAL); - if ( - $daysBetweenSettlementAndMaturity > Helpers::daysPerYear(DateTime::YEAR($maturity), Helpers::DAYS_PER_YEAR_ACTUAL) || - $daysBetweenSettlementAndMaturity < 0 - ) { + if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { return Functions::NAN(); } + $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); if ($price < 0.0) { return Functions::NAN(); @@ -127,11 +125,11 @@ class TreasuryBill $maturity = Functions::flattenSingleValue($maturity); $price = Functions::flattenSingleValue($price); - if ( - is_string($maturity = DateTime::getDateValue($maturity)) || - is_string($settlement = DateTime::getDateValue($settlement)) - ) { - return Functions::VALUE(); + try { + $maturity = DateTimeExcel\Helpers::getDateValue($maturity); + $settlement = DateTimeExcel\Helpers::getDateValue($settlement); + } catch (Exception $e) { + return $e->getMessage(); } // Validate @@ -141,8 +139,9 @@ class TreasuryBill } $daysBetweenSettlementAndMaturity = $maturity - $settlement; + $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($maturity), Helpers::DAYS_PER_YEAR_ACTUAL); - if ($daysBetweenSettlementAndMaturity > 360 || $daysBetweenSettlementAndMaturity < 0) { + if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php b/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php index 0d591b77..026cb9a2 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php @@ -33,7 +33,7 @@ class Fact $factLoop = floor($factVal); if ($factVal > $factLoop) { if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - return Statistical::GAMMAFunction($factVal + 1); + return Statistical\Distributions\Gamma::gammaValue($factVal + 1); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index ca160c36..695d7cbd 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -946,7 +946,7 @@ class Statistical { $aArgs = Functions::flattenArray($args); - $aMean = MathTrig::PRODUCT($aArgs); + $aMean = MathTrig\Product::funcProduct($aArgs); if (is_numeric($aMean) && ($aMean > 0)) { $aCount = Counts::COUNT($aArgs); if (Minimum::MIN($aArgs) > 0) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php index 1ba7adca..51d097b3 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php @@ -44,12 +44,12 @@ class Poisson $summer = 0; $floor = floor($value); for ($i = 0; $i <= $floor; ++$i) { - $summer += $mean ** $i / MathTrig::FACT($i); + $summer += $mean ** $i / MathTrig\Fact::funcFact($i); } return exp(0 - $mean) * $summer; } - return (exp(0 - $mean) * $mean ** $value) / MathTrig::FACT($value); + return (exp(0 - $mean) * $mean ** $value) / MathTrig\Fact::funcFact($value); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php index 5d03e5d5..343a056c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -32,7 +32,7 @@ class Permutations return Functions::NAN(); } - return round(MathTrig::FACT($numObjs) / MathTrig::FACT($numObjs - $numInSet)); + return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)); } return Functions::VALUE(); diff --git a/src/PhpSpreadsheet/Calculation/TextData/Format.php b/src/PhpSpreadsheet/Calculation/TextData/Format.php index f24ed7ae..c061818e 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Format.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -3,7 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\TextData; use DateTimeInterface; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; use PhpOffice\PhpSpreadsheet\Shared\Date; @@ -96,7 +96,7 @@ class Format $format = Functions::flattenSingleValue($format); if ((is_string($value)) && (!is_numeric($value)) && Date::isDateTimeFormatCode($format)) { - $value = DateTime::DATEVALUE($value); + $value = DateTimeExcel\DateValue::funcDateValue($value); } return (string) NumberFormat::toFormattedString($value, $format); @@ -127,14 +127,14 @@ class Format Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); if (strpos($value, ':') !== false) { - $timeValue = DateTime::TIMEVALUE($value); + $timeValue = DateTimeExcel\TimeValue::funcTimeValue($value); if ($timeValue !== Functions::VALUE()) { Functions::setReturnDateType($dateSetting); return $timeValue; } } - $dateValue = DateTime::DATEVALUE($value); + $dateValue = DateTimeExcel\DateValue::funcDateValue($value); if ($dateValue !== Functions::VALUE()) { Functions::setReturnDateType($dateSetting); diff --git a/src/PhpSpreadsheet/Calculation/TextData/Replace.php b/src/PhpSpreadsheet/Calculation/TextData/Replace.php index a06d4364..a1975d6b 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Replace.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Replace.php @@ -3,7 +3,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\TextData; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\TextData; class Replace { @@ -23,7 +22,7 @@ class Replace $newText = Functions::flattenSingleValue($newText); $left = Extract::left($oldText, $start - 1); - $right = Extract::right($oldText, TextData::STRINGLENGTH($oldText) - ($start + $chars) + 1); + $right = Extract::right($oldText, Text::length($oldText) - ($start + $chars) + 1); return $left . $newText . $right; } diff --git a/src/PhpSpreadsheet/Shared/Date.php b/src/PhpSpreadsheet/Shared/Date.php index 28c39255..a6cacb6f 100644 --- a/src/PhpSpreadsheet/Shared/Date.php +++ b/src/PhpSpreadsheet/Shared/Date.php @@ -2,9 +2,10 @@ namespace PhpOffice\PhpSpreadsheet\Shared; +use DateTime; use DateTimeInterface; use DateTimeZone; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; @@ -154,7 +155,7 @@ class Date * if you don't want to treat it as a UTC value * Use the default (UST) unless you absolutely need a conversion * - * @return \DateTime PHP date/time object + * @return DateTime PHP date/time object */ public static function excelToDateTimeObject($excelTimestamp, $timeZone = null) { @@ -162,18 +163,18 @@ class Date if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) { if ($excelTimestamp < 1 && self::$excelCalendar === self::CALENDAR_WINDOWS_1900) { // Unix timestamp base date - $baseDate = new \DateTime('1970-01-01', $timeZone); + $baseDate = new DateTime('1970-01-01', $timeZone); } else { // MS Excel calendar base dates if (self::$excelCalendar == self::CALENDAR_WINDOWS_1900) { // Allow adjustment for 1900 Leap Year in MS Excel - $baseDate = ($excelTimestamp < 60) ? new \DateTime('1899-12-31', $timeZone) : new \DateTime('1899-12-30', $timeZone); + $baseDate = ($excelTimestamp < 60) ? new DateTime('1899-12-31', $timeZone) : new DateTime('1899-12-30', $timeZone); } else { - $baseDate = new \DateTime('1904-01-01', $timeZone); + $baseDate = new DateTime('1904-01-01', $timeZone); } } } else { - $baseDate = new \DateTime('1899-12-30', $timeZone); + $baseDate = new DateTime('1899-12-30', $timeZone); } $days = floor($excelTimestamp); @@ -262,7 +263,7 @@ class Date return false; } - return self::dateTimeToExcel(new \DateTime('@' . $dateValue)); + return self::dateTimeToExcel(new DateTime('@' . $dateValue)); } /** @@ -436,14 +437,14 @@ class Date return false; } - $dateValueNew = DateTime::DATEVALUE($dateValue); + $dateValueNew = DateTimeExcel\DateValue::funcDateValue($dateValue); if ($dateValueNew === Functions::VALUE()) { return false; } if (strpos($dateValue, ':') !== false) { - $timeValue = DateTime::TIMEVALUE($dateValue); + $timeValue = DateTimeExcel\TimeValue::funcTimeValue($dateValue); if ($timeValue === Functions::VALUE()) { return false; } diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/src/PhpSpreadsheet/Worksheet/AutoFilter.php index 4c33eb37..22fc775c 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -3,7 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException; @@ -472,7 +472,7 @@ class AutoFilter $val = $maxVal = null; $ruleValues = []; - $baseDate = DateTime::DATENOW(); + $baseDate = DateTimeExcel\Now::funcNow(); // Calculate start/end dates for the required date range based on current date switch ($dynamicRuleType) { case AutoFilter\Column\Rule::AUTOFILTER_RULETYPE_DYNAMIC_LASTWEEK: From c699d144e20967afa83cee17d6dbf01192b614eb Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 26 Mar 2021 22:49:16 +0100 Subject: [PATCH 137/187] Extract ACCRINT() and ACCRINTM() Financial functions into their own class (#1956) * Extract ACCRINT() and ACCRINTM() Financial functions into their own class Implement additional validations, with additional unit tests Add support for the new calculation method argument for ACCRINT() * Additional tests for Amortization functions --- .../Calculation/Calculation.php | 6 +- .../Engineering/BaseValidations.php | 27 ++++ .../Calculation/Engineering/BesselI.php | 25 +-- .../Calculation/Engineering/BesselJ.php | 25 +-- .../Calculation/Engineering/BesselK.php | 30 ++-- .../Calculation/Engineering/BesselY.php | 30 ++-- .../Calculation/Engineering/Compare.php | 17 ++- .../Calculation/Engineering/Complex.php | 15 +- .../Calculation/Engineering/Erf.php | 6 +- src/PhpSpreadsheet/Calculation/Financial.php | 126 +++++++-------- .../Calculation/Financial/Amortization.php | 27 ++++ .../Calculation/Financial/BaseValidations.php | 72 +++++++++ .../Calculation/Financial/Coupons.php | 76 +--------- .../Calculation/Financial/Depreciation.php | 38 +---- .../Calculation/Financial/Helpers.php | 15 ++ .../Calculation/Financial/InterestRate.php | 25 +-- .../Financial/Securities/AccruedInterest.php | 143 ++++++++++++++++++ .../Financial/Securities/BaseValidations.php | 58 ++++--- .../Financial/Securities/Price.php | 4 +- .../Financial/Securities/Yields.php | 4 +- .../Calculation/Financial/TreasuryBill.php | 14 +- .../Functions/Financial/AccrintMTest.php | 2 +- .../Functions/Financial/AccrintTest.php | 2 +- tests/data/Calculation/Financial/ACCRINT.php | 113 +++++++------- tests/data/Calculation/Financial/ACCRINTM.php | 59 +++++--- .../data/Calculation/Financial/AMORDEGRC.php | 12 ++ .../data/Calculation/Financial/COUPDAYBS.php | 4 +- tests/data/Calculation/Financial/COUPDAYS.php | 4 +- .../data/Calculation/Financial/COUPDAYSNC.php | 4 +- tests/data/Calculation/Financial/COUPNCD.php | 4 +- tests/data/Calculation/Financial/COUPNUM.php | 4 +- tests/data/Calculation/Financial/COUPPCD.php | 4 +- 32 files changed, 625 insertions(+), 370 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 3cce499f..e1ccb74b 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -233,12 +233,12 @@ class Calculation ], 'ACCRINT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'ACCRINT'], - 'argumentCount' => '4-7', + 'functionCall' => [Financial\Securities\AccruedInterest::class, 'periodic'], + 'argumentCount' => '4-8', ], 'ACCRINTM' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'ACCRINTM'], + 'functionCall' => [Financial\Securities\AccruedInterest::class, 'atMaturity'], 'argumentCount' => '3-5', ], 'ACOS' => [ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php new file mode 100644 index 00000000..48317635 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php @@ -0,0 +1,27 @@ +getMessage(); } - return Functions::VALUE(); + if ($ord < 0) { + return Functions::NAN(); + } + + $fResult = self::calculate($x, $ord); + + return (is_nan($fResult)) ? Functions::NAN() : $fResult; } private static function calculate(float $x, int $ord): float diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php index 5e8bfbf5..ca9ff4f7 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselJ { + use BaseValidations; + /** * BESSELJ. * @@ -30,18 +33,20 @@ class BesselJ $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); - if ((is_numeric($x)) && (is_numeric($ord))) { - $ord = (int) floor($ord); - if ($ord < 0) { - return Functions::NAN(); - } - - $fResult = self::calculate((float) $x, $ord); - - return (is_nan($fResult)) ? Functions::NAN() : $fResult; + try { + $x = self::validateFloat($x); + $ord = self::validateInt($ord); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if ($ord < 0) { + return Functions::NAN(); + } + + $fResult = self::calculate($x, $ord); + + return (is_nan($fResult)) ? Functions::NAN() : $fResult; } private static function calculate(float $x, int $ord): float diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php index ff32b78a..faba191f 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselK { + use BaseValidations; + /** * BESSELK. * @@ -28,25 +31,26 @@ class BesselK $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); - if ((is_numeric($x)) && (is_numeric($ord))) { - $ord = (int) floor($ord); - $x = (float) $x; - if (($ord < 0) || ($x <= 0.0)) { - return Functions::NAN(); - } - - $fBk = self::calculate($x, $ord); - - return (is_nan($fBk)) ? Functions::NAN() : $fBk; + try { + $x = self::validateFloat($x); + $ord = self::validateInt($ord); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if (($ord < 0) || ($x <= 0.0)) { + return Functions::NAN(); + } + + $fBk = self::calculate($x, $ord); + + return (is_nan($fBk)) ? Functions::NAN() : $fBk; } - private static function calculate($x, $ord): float + private static function calculate(float $x, int $ord): float { // special cases - switch (floor($ord)) { + switch ($ord) { case 0: return self::besselK0($x); case 1: diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php index 09694381..1eed5a54 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselY { + use BaseValidations; + /** * BESSELY. * @@ -27,25 +30,26 @@ class BesselY $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); - if ((is_numeric($x)) && (is_numeric($ord))) { - $ord = (int) floor($ord); - $x = (float) $x; - if (($ord < 0) || ($x <= 0.0)) { - return Functions::NAN(); - } - - $fBy = self::calculate($x, $ord); - - return (is_nan($fBy)) ? Functions::NAN() : $fBy; + try { + $x = self::validateFloat($x); + $ord = self::validateInt($ord); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if (($ord < 0) || ($x <= 0.0)) { + return Functions::NAN(); + } + + $fBy = self::calculate($x, $ord); + + return (is_nan($fBy)) ? Functions::NAN() : $fBy; } - private static function calculate($x, $ord): float + private static function calculate(float $x, int $ord): float { // special cases - switch (floor($ord)) { + switch ($ord) { case 0: return self::besselY0($x); case 1: diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Compare.php b/src/PhpSpreadsheet/Calculation/Engineering/Compare.php index d875174e..c764d8ea 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Compare.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Compare.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Compare { + use BaseValidations; + /** * DELTA. * @@ -27,8 +30,11 @@ class Compare $a = Functions::flattenSingleValue($a); $b = Functions::flattenSingleValue($b); - if (!is_numeric($a) || !is_numeric($b)) { - return Functions::VALUE(); + try { + $a = self::validateFloat($a); + $b = self::validateFloat($b); + } catch (Exception $e) { + return $e->getMessage(); } return (int) ($a == $b); @@ -54,8 +60,11 @@ class Compare $number = Functions::flattenSingleValue($number); $step = Functions::flattenSingleValue($step); - if (!is_numeric($number) || !is_numeric($step)) { - return Functions::VALUE(); + try { + $number = self::validateFloat($number); + $step = self::validateFloat($step); + } catch (Exception $e) { + return $e->getMessage(); } return (int) ($number >= $step); diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php index 7dd5ff95..a1a64768 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php @@ -4,10 +4,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; use Complex\Complex as ComplexObject; use Complex\Exception as ComplexException; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Complex { + use BaseValidations; + /** * COMPLEX. * @@ -29,10 +32,14 @@ class Complex $imaginary = ($imaginary === null) ? 0.0 : Functions::flattenSingleValue($imaginary); $suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix); - if ( - ((is_numeric($realNumber)) && (is_numeric($imaginary))) && - (($suffix == 'i') || ($suffix == 'j') || ($suffix == '')) - ) { + try { + $realNumber = self::validateFloat($realNumber); + $imaginary = self::validateFloat($imaginary); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (($suffix == 'i') || ($suffix == 'j') || ($suffix == '')) { $complex = new ComplexObject($realNumber, $imaginary, $suffix); return (string) $complex; diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Erf.php b/src/PhpSpreadsheet/Calculation/Engineering/Erf.php index 54358ebd..a5df425e 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Erf.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Erf.php @@ -21,8 +21,8 @@ class Erf * Excel Function: * ERF(lower[,upper]) * - * @param float $lower lower bound for integrating ERF - * @param float $upper upper bound for integrating ERF. + * @param mixed (float) $lower lower bound for integrating ERF + * @param mixed (float) $upper upper bound for integrating ERF. * If omitted, ERF integrates between zero and lower_limit * * @return float|string @@ -52,7 +52,7 @@ class Erf * Excel Function: * ERF.PRECISE(limit) * - * @param float $limit bound for integrating ERF + * @param mixed (float) $limit bound for integrating ERF * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 084562f8..1a67ef33 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -35,57 +35,58 @@ class Financial * Returns the accrued interest for a security that pays periodic interest. * * Excel Function: - * ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis]) + * ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis][,calc_method]) + * + * @Deprecated 1.18.0 + * + * @see Financial\Securities\AccruedInterest::periodic() + * Use the periodic() method in the Financial\Securities\AccruedInterest class instead * * @param mixed $issue the security's issue date * @param mixed $firstinterest the security's first interest date * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue date - * when the security is traded to the buyer. + * The security settlement date is the date after the issue date + * when the security is traded to the buyer. * @param mixed (float) $rate the security's annual coupon rate * @param mixed (float) $par The security's par value. - * If you omit par, ACCRINT uses $1,000. - * @param mixed (int) $frequency the number of coupon payments per year. + * If you omit par, ACCRINT uses $1,000. + * @param mixed (int) $frequency The number of coupon payments per year. * Valid frequency values are: * 1 Annual * 2 Semi-Annual * 4 Quarterly * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @param mixed (bool) $calcMethod + * If true, use Issue to Settlement + * If false, use FirstInterest to Settlement * * @return float|string Result, or a string containing an error */ - public static function ACCRINT($issue, $firstinterest, $settlement, $rate, $par = 1000, $frequency = 1, $basis = 0) - { - $issue = Functions::flattenSingleValue($issue); - $firstinterest = Functions::flattenSingleValue($firstinterest); - $settlement = Functions::flattenSingleValue($settlement); - $rate = Functions::flattenSingleValue($rate); - $par = ($par === null) ? 1000 : Functions::flattenSingleValue($par); - $frequency = ($frequency === null) ? 1 : Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); - - // Validate - if ((is_numeric($rate)) && (is_numeric($par))) { - $rate = (float) $rate; - $par = (float) $par; - if (($rate <= 0) || ($par <= 0)) { - return Functions::NAN(); - } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - // return date error - return $daysBetweenIssueAndSettlement; - } - - return $par * $rate * $daysBetweenIssueAndSettlement; - } - - return Functions::VALUE(); + public static function ACCRINT( + $issue, + $firstinterest, + $settlement, + $rate, + $par = 1000, + $frequency = 1, + $basis = 0, + $calcMethod = true + ) { + return Securities\AccruedInterest::periodic( + $issue, + $firstinterest, + $settlement, + $rate, + $par, + $frequency, + $basis, + $calcMethod + ); } /** @@ -96,45 +97,28 @@ class Financial * Excel Function: * ACCRINTM(issue,settlement,rate[,par[,basis]]) * + * @Deprecated 1.18.0 + * + * @see Financial\Securities\AccruedInterest::atMaturity() + * Use the atMaturity() method in the Financial\Securities\AccruedInterest class instead + * * @param mixed $issue The security's issue date * @param mixed $settlement The security's settlement (or maturity) date * @param mixed (float) $rate The security's annual coupon rate * @param mixed (float) $par The security's par value. - * If you omit par, ACCRINT uses $1,000. + * If you omit par, ACCRINT uses $1,000. * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0) { - $issue = Functions::flattenSingleValue($issue); - $settlement = Functions::flattenSingleValue($settlement); - $rate = Functions::flattenSingleValue($rate); - $par = ($par === null) ? 1000 : Functions::flattenSingleValue($par); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); - - // Validate - if ((is_numeric($rate)) && (is_numeric($par))) { - $rate = (float) $rate; - $par = (float) $par; - if (($rate <= 0) || ($par <= 0)) { - return Functions::NAN(); - } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); - if (!is_numeric($daysBetweenIssueAndSettlement)) { - // return date error - return $daysBetweenIssueAndSettlement; - } - - return $par * $rate * $daysBetweenIssueAndSettlement; - } - - return Functions::VALUE(); + return Securities\AccruedInterest::atMaturity($issue, $settlement, $rate, $par, $basis); } /** @@ -163,11 +147,11 @@ class Financial * @param float $period The period * @param float $rate Rate of depreciation * @param int $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string (string containing the error type if there is an error) */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php index f1a9e3f5..9e838a26 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php @@ -3,10 +3,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Amortization { + use BaseValidations; + /** * AMORDEGRC. * @@ -47,6 +50,18 @@ class Amortization $rate = Functions::flattenSingleValue($rate); $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); + try { + $cost = self::validateFloat($cost); + $purchased = self::validateDate($purchased); + $firstPeriod = self::validateDate($firstPeriod); + $salvage = self::validateFloat($salvage); + $period = self::validateFloat($period); + $rate = self::validateFloat($rate); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + $yearFrac = DateTimeExcel\YearFrac::funcYearFrac($purchased, $firstPeriod, $basis); if (is_string($yearFrac)) { return $yearFrac; @@ -113,6 +128,18 @@ class Amortization $rate = Functions::flattenSingleValue($rate); $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); + try { + $cost = self::validateFloat($cost); + $purchased = self::validateDate($purchased); + $firstPeriod = self::validateDate($firstPeriod); + $salvage = self::validateFloat($salvage); + $period = self::validateFloat($period); + $rate = self::validateFloat($rate); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + $fOneRate = $cost * $rate; $fCostDelta = $cost - $salvage; // Note, quirky variation for leap years on the YEARFRAC for this function diff --git a/src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php new file mode 100644 index 00000000..01d9ab30 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php @@ -0,0 +1,72 @@ + 4)) { + throw new Exception(Functions::NAN()); + } + + return $basis; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php index c4a60d90..ce83ccb4 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -2,7 +2,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; -use DateTime; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -10,6 +9,8 @@ use PhpOffice\PhpSpreadsheet\Shared\Date; class Coupons { + use BaseValidations; + public const FREQUENCY_ANNUAL = 1; public const FREQUENCY_SEMI_ANNUAL = 2; public const FREQUENCY_QUARTERLY = 4; @@ -62,6 +63,9 @@ class Coupons } $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); + if (is_string($daysPerYear)) { + return Functions::VALUE(); + } $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); if ($basis === Helpers::DAYS_PER_YEAR_ACTUAL) { @@ -185,7 +189,7 @@ class Coupons if ($basis === Helpers::DAYS_PER_YEAR_NASD) { $settlementDate = Date::excelToDateTimeObject($settlement); - $settlementEoM = self::isLastDayOfMonth($settlementDate); + $settlementEoM = Helpers::isLastDayOfMonth($settlementDate); if ($settlementEoM) { ++$settlement; } @@ -340,26 +344,12 @@ class Coupons return self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); } - /** - * isLastDayOfMonth. - * - * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month - * - * @param DateTime $testDate The date for testing - * - * @return bool - */ - private static function isLastDayOfMonth(DateTime $testDate) - { - return $testDate->format('d') === $testDate->format('t'); - } - private static function couponFirstPeriodDate($settlement, $maturity, int $frequency, $next) { $months = 12 / $frequency; $result = Date::excelToDateTimeObject($maturity); - $maturityEoM = self::isLastDayOfMonth($result); + $maturityEoM = Helpers::isLastDayOfMonth($result); while ($settlement < Date::PHPToExcel($result)) { $result->modify('-' . $months . ' months'); @@ -375,62 +365,10 @@ class Coupons return Date::PHPToExcel($result); } - private static function validateInputDate($date) - { - $date = DateTimeExcel\Helpers::getDateValue($date); - if (is_string($date)) { - throw new Exception(Functions::VALUE()); - } - - return $date; - } - - private static function validateSettlementDate($settlement) - { - return self::validateInputDate($settlement); - } - - private static function validateMaturityDate($maturity) - { - return self::validateInputDate($maturity); - } - private static function validateCouponPeriod($settlement, $maturity): void { if ($settlement >= $maturity) { throw new Exception(Functions::NAN()); } } - - private static function validateFrequency($frequency): int - { - if (!is_numeric($frequency)) { - throw new Exception(Functions::NAN()); - } - - $frequency = (int) $frequency; - if ( - ($frequency !== self::FREQUENCY_ANNUAL) && - ($frequency !== self::FREQUENCY_SEMI_ANNUAL) && - ($frequency !== self::FREQUENCY_QUARTERLY) - ) { - throw new Exception(Functions::NAN()); - } - - return $frequency; - } - - private static function validateBasis($basis): int - { - if (!is_numeric($basis)) { - throw new Exception(Functions::NAN()); - } - - $basis = (int) $basis; - if (($basis < 0) || ($basis > 4)) { - throw new Exception(Functions::NAN()); - } - - return $basis; - } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php index 8770242f..89dc226c 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php @@ -7,6 +7,8 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Depreciation { + use BaseValidations; + /** * DB. * @@ -203,11 +205,7 @@ class Depreciation private static function validateCost($cost, bool $negativeValueAllowed = false): float { - if (!is_numeric($cost)) { - throw new Exception(Functions::VALUE()); - } - - $cost = (float) $cost; + $cost = self::validateFloat($cost); if ($cost < 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -217,11 +215,7 @@ class Depreciation private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float { - if (!is_numeric($salvage)) { - throw new Exception(Functions::VALUE()); - } - - $salvage = (float) $salvage; + $salvage = self::validateFloat($salvage); if ($salvage < 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -231,11 +225,7 @@ class Depreciation private static function validateLife($life, bool $negativeValueAllowed = false): float { - if (!is_numeric($life)) { - throw new Exception(Functions::VALUE()); - } - - $life = (float) $life; + $life = self::validateFloat($life); if ($life < 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -245,11 +235,7 @@ class Depreciation private static function validatePeriod($period, bool $negativeValueAllowed = false): float { - if (!is_numeric($period)) { - throw new Exception(Functions::VALUE()); - } - - $period = (float) $period; + $period = self::validateFloat($period); if ($period <= 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -259,11 +245,7 @@ class Depreciation private static function validateMonth($month): int { - if (!is_numeric($month)) { - throw new Exception(Functions::VALUE()); - } - - $month = (int) $month; + $month = self::validateInt($month); if ($month < 1) { throw new Exception(Functions::NAN()); } @@ -273,11 +255,7 @@ class Depreciation private static function validateFactor($factor): float { - if (!is_numeric($factor)) { - throw new Exception(Functions::VALUE()); - } - - $factor = (float) $factor; + $factor = self::validateFloat($factor); if ($factor <= 0.0) { throw new Exception(Functions::NAN()); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Helpers.php b/src/PhpSpreadsheet/Calculation/Financial/Helpers.php index 08c942ab..79ef61e3 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Helpers.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; +use DateTimeInterface; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -47,4 +48,18 @@ class Helpers return Functions::NAN(); } + + /** + * isLastDayOfMonth. + * + * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month + * + * @param DateTimeInterface $date The date for testing + * + * @return bool + */ + public static function isLastDayOfMonth(DateTimeInterface $date) + { + return $date->format('d') === $date->format('t'); + } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php index 04b43e32..ed0fec75 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php +++ b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php @@ -2,10 +2,13 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class InterestRate { + use BaseValidations; + /** * EFFECT. * @@ -25,16 +28,17 @@ class InterestRate $nominalRate = Functions::flattenSingleValue($nominalRate); $periodsPerYear = Functions::flattenSingleValue($periodsPerYear); - // Validate parameters - if (!is_numeric($nominalRate) || !is_numeric($periodsPerYear)) { - return Functions::VALUE(); + try { + $nominalRate = self::validateFloat($nominalRate); + $periodsPerYear = self::validateInt($periodsPerYear); + } catch (Exception $e) { + return $e->getMessage(); } + if ($nominalRate <= 0 || $periodsPerYear < 1) { return Functions::NAN(); } - $periodsPerYear = (int) $periodsPerYear; - return ((1 + $nominalRate / $periodsPerYear) ** $periodsPerYear) - 1; } @@ -53,16 +57,17 @@ class InterestRate $effectiveRate = Functions::flattenSingleValue($effectiveRate); $periodsPerYear = Functions::flattenSingleValue($periodsPerYear); - // Validate parameters - if (!is_numeric($effectiveRate) || !is_numeric($periodsPerYear)) { - return Functions::VALUE(); + try { + $effectiveRate = self::validateFloat($effectiveRate); + $periodsPerYear = self::validateInt($periodsPerYear); + } catch (Exception $e) { + return $e->getMessage(); } + if ($effectiveRate <= 0 || $periodsPerYear < 1) { return Functions::NAN(); } - $periodsPerYear = (int) $periodsPerYear; - // Calculate return $periodsPerYear * (($effectiveRate + 1) ** (1 / $periodsPerYear) - 1); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php new file mode 100644 index 00000000..f81ea13c --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php @@ -0,0 +1,143 @@ +getMessage(); + } + + $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + $daysBetweenFirstInterestAndSettlement = DateTime::YEARFRAC($firstinterest, $settlement, $basis); + if (!is_numeric($daysBetweenFirstInterestAndSettlement)) { + // return date error + return $daysBetweenFirstInterestAndSettlement; + } + + return $parValue * $rate * $daysBetweenIssueAndSettlement; + } + + /** + * ACCRINTM. + * + * Returns the accrued interest for a security that pays interest at maturity. + * + * Excel Function: + * ACCRINTM(issue,settlement,rate[,par[,basis]]) + * + * @param mixed $issue The security's issue date + * @param mixed $settlement The security's settlement (or maturity) date + * @param mixed (float) $rate The security's annual coupon rate + * @param mixed (float) $par The security's par value. + * If you omit par, ACCRINT uses $1,000. + * @param mixed (int) $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * @param mixed $parValue + * + * @return float|string Result, or a string containing an error + */ + public static function atMaturity($issue, $settlement, $rate, $parValue = 1000, $basis = 0) + { + $issue = Functions::flattenSingleValue($issue); + $settlement = Functions::flattenSingleValue($settlement); + $rate = Functions::flattenSingleValue($rate); + $parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue); + $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + + try { + $issue = self::validateIssueDate($issue); + $settlement = self::validateSettlementDate($settlement); + self::validateSecurityPeriod($issue, $settlement); + $rate = self::validateRate($rate); + $parValue = self::validateParValue($parValue); + $basis = self::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + if (!is_numeric($daysBetweenIssueAndSettlement)) { + // return date error + return $daysBetweenIssueAndSettlement; + } + + return $parValue * $rate * $daysBetweenIssueAndSettlement; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php index 2a5e5dd2..bd197d7f 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php @@ -7,31 +7,35 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants as SecuritiesConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -abstract class BaseValidations +trait BaseValidations { - protected static function validateInputDate($date) + protected static function validateDate($date) { - $date = DateTimeExcel\Helpers::getDateValue($date); - if (is_string($date)) { + return DateTimeExcel\Helpers::getDateValue($date); + } + + protected static function validateFloat($value): float + { + if (!is_numeric($value)) { throw new Exception(Functions::VALUE()); } - return $date; + return (float) $value; } protected static function validateSettlementDate($settlement) { - return self::validateInputDate($settlement); + return self::validateDate($settlement); } protected static function validateMaturityDate($maturity) { - return self::validateInputDate($maturity); + return self::validateDate($maturity); } protected static function validateIssueDate($issue) { - return self::validateInputDate($issue); + return self::validateDate($issue); } protected static function validateSecurityPeriod($settlement, $maturity): void @@ -43,11 +47,7 @@ abstract class BaseValidations protected static function validateRate($rate): float { - if (!is_numeric($rate)) { - throw new Exception(Functions::VALUE()); - } - - $rate = (float) $rate; + $rate = self::validateFloat($rate); if ($rate < 0.0) { throw new Exception(Functions::NAN()); } @@ -55,13 +55,19 @@ abstract class BaseValidations return $rate; } - protected static function validatePrice($price): float + protected static function validateParValue($parValue): float { - if (!is_numeric($price)) { - throw new Exception(Functions::VALUE()); + $parValue = self::validateFloat($parValue); + if ($parValue < 0.0) { + throw new Exception(Functions::NAN()); } - $price = (float) $price; + return $parValue; + } + + protected static function validatePrice($price): float + { + $price = self::validateFloat($price); if ($price < 0.0) { throw new Exception(Functions::NAN()); } @@ -71,11 +77,7 @@ abstract class BaseValidations protected static function validateYield($yield): float { - if (!is_numeric($yield)) { - throw new Exception(Functions::VALUE()); - } - - $yield = (float) $yield; + $yield = self::validateFloat($yield); if ($yield < 0.0) { throw new Exception(Functions::NAN()); } @@ -85,11 +87,7 @@ abstract class BaseValidations protected static function validateRedemption($redemption): float { - if (!is_numeric($redemption)) { - throw new Exception(Functions::VALUE()); - } - - $redemption = (float) $redemption; + $redemption = self::validateFloat($redemption); if ($redemption <= 0.0) { throw new Exception(Functions::NAN()); } @@ -99,11 +97,7 @@ abstract class BaseValidations protected static function validateDiscount($discount): float { - if (!is_numeric($discount)) { - throw new Exception(Functions::VALUE()); - } - - $discount = (float) $discount; + $discount = self::validateFloat($discount); if ($discount <= 0.0) { throw new Exception(Functions::NAN()); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php index 18a0a2e1..6b04d6d9 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php @@ -8,8 +8,10 @@ use PhpOffice\PhpSpreadsheet\Calculation\Financial\Coupons; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -class Price extends BaseValidations +class Price { + use BaseValidations; + /** * PRICE. * diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php index 86151904..46c3bb05 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php @@ -7,8 +7,10 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -class Yields extends BaseValidations +class Yields { + use BaseValidations; + /** * YIELDDISC. * diff --git a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php index 966500bf..8fd47ba6 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php +++ b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php @@ -8,6 +8,8 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class TreasuryBill { + use BaseValidations; + /** * TBILLEQ. * @@ -29,8 +31,8 @@ class TreasuryBill $discount = Functions::flattenSingleValue($discount); try { - $maturity = DateTimeExcel\Helpers::getDateValue($maturity); - $settlement = DateTimeExcel\Helpers::getDateValue($settlement); + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); } catch (Exception $e) { return $e->getMessage(); } @@ -75,8 +77,8 @@ class TreasuryBill $discount = Functions::flattenSingleValue($discount); try { - $maturity = DateTimeExcel\Helpers::getDateValue($maturity); - $settlement = DateTimeExcel\Helpers::getDateValue($settlement); + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); } catch (Exception $e) { return $e->getMessage(); } @@ -126,8 +128,8 @@ class TreasuryBill $price = Functions::flattenSingleValue($price); try { - $maturity = DateTimeExcel\Helpers::getDateValue($maturity); - $settlement = DateTimeExcel\Helpers::getDateValue($settlement); + $settlement = self::validateSettlementDate($settlement); + $maturity = self::validateMaturityDate($maturity); } catch (Exception $e) { return $e->getMessage(); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php index 597db5c2..908e4862 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php @@ -21,7 +21,7 @@ class AccrintMTest extends TestCase public function testACCRINTM($expectedResult, ...$args): void { $result = Financial::ACCRINTM(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } public function providerACCRINTM() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php index edb79230..2d31c4cc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php @@ -21,7 +21,7 @@ class AccrintTest extends TestCase public function testACCRINT($expectedResult, ...$args): void { $result = Financial::ACCRINT(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-8); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } public function providerACCRINT() diff --git a/tests/data/Calculation/Financial/ACCRINT.php b/tests/data/Calculation/Financial/ACCRINT.php index 58f6b636..1852e7e3 100644 --- a/tests/data/Calculation/Financial/ACCRINT.php +++ b/tests/data/Calculation/Financial/ACCRINT.php @@ -4,72 +4,83 @@ return [ [ - 16.666666666666998, - '2008-03-01', - '2008-08-31', - '2008-05-01', - 0.10000000000000001, - 1000, - 2, - 0, + 16.6666666666666, + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, ], [ - 15.555555555555999, - '2008-03-05', - '2008-08-31', - '2008-05-01', - 0.10000000000000001, - 1000, - 2, - 0, + 15.5555555555559, + '2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, + ], + [ + 15.5555555555559, + '2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, true, + ], + [ + 7.22222222222222, + '2008-04-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, true, ], [ 200, - '2010-01-01', - '2010-06-30', - '2010-04-01', - 0.080000000000000002, - 10000, - 4, + '2010-01-01', '2010-06-30', '2010-04-01', 0.08, 10000, 4, + ], + [ + 1600, + '2012-01-01', '2012-04-01', '2013-12-31', 0.08, 10000, 4, + ], + [ + 32.363013698630134, + '2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 5000, 4, 3, 1, + ], + [ + 6.472602739726027, + '2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 1000, 4, 3, 1, + ], + [ + 18.05555555555555, + '2017-08-05', '2017-11-10', '2017-10-10', 0.05, 2000, 4, 0, 1, ], [ '#NUM!', - '2008-03-05', - '2008-08-31', - '2008-05-01', - -0.10000000000000001, - 1000, - 2, - 0, + '2008-03-05', '2008-08-31', '2008-05-01', -0.10, 1000, 2, 0, ], [ '#VALUE!', - 'Invalid Date', - '2008-08-31', - '2008-05-01', - 0.10000000000000001, - 1000, - 2, - 0, + 'Invalid Date', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, ], [ '#VALUE!', - '2008-03-01', - '2008-08-31', - '2008-05-01', - 'ABC', - 1000, - 2, - 0, + '2008-03-01', '2008-08-31', '2008-05-01', 'ABC', 1000, 2, 0, ], - [ + 'Non-numeric Rate' => [ '#VALUE!', - '2008-03-01', - '2008-08-31', - '2008-05-01', - 0.10000000000000001, - 1000, - 2, - 'ABC', + '2008-03-01', '2008-08-31', '2008-05-01', 'NaN', 1000, 2, 0, + ], + 'Invalid Rate' => [ + '#NUM!', + '2008-03-01', '2008-08-31', '2008-05-01', -0.10, 1000, 2, 0, + ], + 'Non-numeric Par Value' => [ + '#VALUE!', + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, 'NaN', 2, 0, + ], + 'Invalid Par Value' => [ + '#NUM!', + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, -1000, 2, 0, + ], + 'Non-numeric Frequency' => [ + '#VALUE!', + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 'NaN', 0, + ], + 'Invalid Frequency' => [ + '#NUM!', + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, -1000, 3, 0, + ], + 'Non-numeric Basis' => [ + '#VALUE!', + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 'ABC', + ], + 'Invalid Basis' => [ + '#NUM!', + '2008-03-01', '2008-08-31', '2008-05-01', 0.10, 1000, 2, -2, ], ]; diff --git a/tests/data/Calculation/Financial/ACCRINTM.php b/tests/data/Calculation/Financial/ACCRINTM.php index 7949b1ad..e442b6f8 100644 --- a/tests/data/Calculation/Financial/ACCRINTM.php +++ b/tests/data/Calculation/Financial/ACCRINTM.php @@ -5,41 +5,50 @@ return [ [ 20.547945205478999, - '2008-04-01', - '2008-06-15', - 0.10000000000000001, - 1000, - 3, + '2008-04-01', '2008-06-15', 0.10, 1000, 3, ], [ 800, - '2010-01-01', - '2010-12-31', - 0.080000000000000002, - 10000, + '2010-01-01', '2010-12-31', 0.08, 10000, + ], + [ + 365.958904109589, + '2012-01-01', '2013-02-15', 0.065, 5000, 3, + ], + [ + 73.1917808219178, + '2012-01-01', '2013-02-15', 0.065, 1000, 3, ], [ '#NUM!', - '2008-03-05', - '2008-08-31', - -0.10000000000000001, - 1000, - 2, + '2008-03-05', '2008-08-31', -0.10, 1000, 2, ], [ '#VALUE!', - 'Invalid Date', - '2008-08-31', - 0.10000000000000001, - 1000, - 2, + 'Invalid Date', '2008-08-31', 0.10, 1000, 2, ], - [ + 'Non-numeric Rate' => [ '#VALUE!', - '2008-03-01', - '2008-08-31', - 'ABC', - 1000, - 2, + '2008-03-01', '2008-08-31', 'NaN', 1000, 2, + ], + 'Invalid Rate' => [ + '#NUM!', + '2008-03-01', '2008-08-31', -0.10, 1000, 2, + ], + 'Non-numeric Par Value' => [ + '#VALUE!', + '2008-03-01', '2008-08-31', 0.10, 'NaN', 2, + ], + 'Invalid Par Value' => [ + '#NUM!', + '2008-03-01', '2008-08-31', 0.10, -1000, 2, + ], + 'Non-numeric Basis' => [ + '#VALUE!', + '2008-03-01', '2008-08-31', 0.10, 1000, 'NaN', + ], + 'Invalid Basis' => [ + '#NUM!', + '2008-03-01', '2008-08-31', 0.10, 1000, 99, ], ]; diff --git a/tests/data/Calculation/Financial/AMORDEGRC.php b/tests/data/Calculation/Financial/AMORDEGRC.php index f4007033..ef3ef1e0 100644 --- a/tests/data/Calculation/Financial/AMORDEGRC.php +++ b/tests/data/Calculation/Financial/AMORDEGRC.php @@ -47,6 +47,14 @@ return [ 42, 150, '2011-01-01', '2011-09-30', 20, 1, 0.4, 4, ], + [ + 2813, + 10000, '2012-03-01', '2012-12-31', 1500, 1, 0.3, 1, + ], + [ + '#VALUE!', + 'NaN', '2012-03-01', '2020-12-25', 20, 1, 0.2, 4, + ], [ '#VALUE!', 550, 'notADate', '2020-12-25', 20, 1, 0.2, 4, @@ -55,4 +63,8 @@ return [ '#VALUE!', 550, '2011-01-01', 'notADate', 20, 1, 0.2, 4, ], + [ + '#VALUE!', + 550, '2012-03-01', '2020-12-25', 'NaN', 1, 0.2, 4, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPDAYBS.php b/tests/data/Calculation/Financial/COUPDAYBS.php index c2208f7d..7a805fdf 100644 --- a/tests/data/Calculation/Financial/COUPDAYBS.php +++ b/tests/data/Calculation/Financial/COUPDAYBS.php @@ -45,7 +45,7 @@ return [ 1, ], 'Non-Numeric Frequency' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 'NaN', @@ -59,7 +59,7 @@ return [ -1, ], 'Non-Numeric Basis' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 4, diff --git a/tests/data/Calculation/Financial/COUPDAYS.php b/tests/data/Calculation/Financial/COUPDAYS.php index acec49d9..2cd2469c 100644 --- a/tests/data/Calculation/Financial/COUPDAYS.php +++ b/tests/data/Calculation/Financial/COUPDAYS.php @@ -59,7 +59,7 @@ return [ 1, ], 'Non-Numeric Frequency' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 'NaN', @@ -73,7 +73,7 @@ return [ -1, ], 'Non-Numeric Basis' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 4, diff --git a/tests/data/Calculation/Financial/COUPDAYSNC.php b/tests/data/Calculation/Financial/COUPDAYSNC.php index 87951dd1..6a7c5bb5 100644 --- a/tests/data/Calculation/Financial/COUPDAYSNC.php +++ b/tests/data/Calculation/Financial/COUPDAYSNC.php @@ -38,7 +38,7 @@ return [ 1, ], 'Non-Numeric Frequency' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 'NaN', @@ -52,7 +52,7 @@ return [ -1, ], 'Non-Numeric Basis' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 4, diff --git a/tests/data/Calculation/Financial/COUPNCD.php b/tests/data/Calculation/Financial/COUPNCD.php index e3d452e5..222c6aa5 100644 --- a/tests/data/Calculation/Financial/COUPNCD.php +++ b/tests/data/Calculation/Financial/COUPNCD.php @@ -38,7 +38,7 @@ return [ 1, ], 'Non-Numeric Frequency' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 'NaN', @@ -52,7 +52,7 @@ return [ -1, ], 'Non-Numeric Basis' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 4, diff --git a/tests/data/Calculation/Financial/COUPNUM.php b/tests/data/Calculation/Financial/COUPNUM.php index b9ad73fa..5af5fd7b 100644 --- a/tests/data/Calculation/Financial/COUPNUM.php +++ b/tests/data/Calculation/Financial/COUPNUM.php @@ -39,7 +39,7 @@ return [ 1, ], 'Non-Numeric Frequency' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 'NaN', @@ -53,7 +53,7 @@ return [ -1, ], 'Non-Numeric Basis' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 4, diff --git a/tests/data/Calculation/Financial/COUPPCD.php b/tests/data/Calculation/Financial/COUPPCD.php index 6d2e2f22..07c00d19 100644 --- a/tests/data/Calculation/Financial/COUPPCD.php +++ b/tests/data/Calculation/Financial/COUPPCD.php @@ -38,7 +38,7 @@ return [ 1, ], 'Non-Numeric Frequency' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 'NaN', @@ -52,7 +52,7 @@ return [ -1, ], 'Non-Numeric Basis' => [ - '#NUM!', + '#VALUE!', '25-Jan-2007', '15-Nov-2008', 4, From ec2531411da6ea57c5d1aa5ec2c7179ee6f58bc4 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 27 Mar 2021 13:29:58 +0100 Subject: [PATCH 138/187] Start implementing Newton-Raphson for the inverse of Statistical Distributions (#1958) * Start implementing Newton-Raphson for the inverse of Statistical Distributions, starting with the two-tailed Student-T * Additional unit tests and validations * Use the new Newton Raphson class for calculating the Inverse of ChiSquared * Extract Weibull distribution, and provide unit tests --- .../Calculation/Calculation.php | 10 +- .../Calculation/Statistical.php | 129 +++--------------- .../Statistical/Distributions/ChiSquared.php | 52 +------ .../Statistical/Distributions/GammaBase.php | 7 +- .../Distributions/NewtonRaphson.php | 62 +++++++++ .../Statistical/Distributions/StudentT.php | 127 +++++++++++++++++ .../Statistical/Distributions/Weibull.php | 51 +++++++ .../Functions/Statistical/TDistTest.php | 28 ++++ .../Functions/Statistical/TinvTest.php | 27 ++++ .../Functions/Statistical/WeibullTest.php | 29 ++++ tests/data/Calculation/Statistical/TDIST.php | 56 ++++++++ tests/data/Calculation/Statistical/TINV.php | 32 +++++ .../data/Calculation/Statistical/WEIBULL.php | 48 +++++++ 13 files changed, 493 insertions(+), 165 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php create mode 100644 tests/data/Calculation/Statistical/TDIST.php create mode 100644 tests/data/Calculation/Statistical/TINV.php create mode 100644 tests/data/Calculation/Statistical/WEIBULL.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index e1ccb74b..6e98fcb0 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -2391,7 +2391,7 @@ class Calculation ], 'TDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'TDIST'], + 'functionCall' => [Statistical\Distributions\StudentT::class, 'distribution'], 'argumentCount' => '3', ], 'T.DIST' => [ @@ -2431,12 +2431,12 @@ class Calculation ], 'TINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'TINV'], + 'functionCall' => [Statistical\Distributions\StudentT::class, 'inverse'], 'argumentCount' => '2', ], 'T.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'TINV'], + 'functionCall' => [Statistical\Distributions\StudentT::class, 'inverse'], 'argumentCount' => '2', ], 'T.INV.2T' => [ @@ -2581,12 +2581,12 @@ class Calculation ], 'WEIBULL' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'WEIBULL'], + 'functionCall' => [Statistical\Distributions\Weibull::class, 'distribution'], 'argumentCount' => '4', ], 'WEIBULL.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'WEIBULL'], + 'functionCall' => [Statistical\Distributions\Weibull::class, 'distribution'], 'argumentCount' => '4', ], 'WORKDAY' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 695d7cbd..5f557431 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -2140,6 +2140,11 @@ class Statistical * * Returns the probability of Student's T distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\StudentT::distribution() + * Use the distribution() method in the Statistical\Distributions\StudentT class instead + * * @param float $value Value for the function * @param float $degrees degrees of freedom * @param float $tails number of tails (1 or 2) @@ -2148,55 +2153,7 @@ class Statistical */ public static function TDIST($value, $degrees, $tails) { - $value = Functions::flattenSingleValue($value); - $degrees = floor(Functions::flattenSingleValue($degrees)); - $tails = floor(Functions::flattenSingleValue($tails)); - - if ((is_numeric($value)) && (is_numeric($degrees)) && (is_numeric($tails))) { - if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) { - return Functions::NAN(); - } - // tdist, which finds the probability that corresponds to a given value - // of t with k degrees of freedom. This algorithm is translated from a - // pascal function on p81 of "Statistical Computing in Pascal" by D - // Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd: - // London). The above Pascal algorithm is itself a translation of the - // fortran algoritm "AS 3" by B E Cooper of the Atlas Computer - // Laboratory as reported in (among other places) "Applied Statistics - // Algorithms", editied by P Griffiths and I D Hill (1985; Ellis - // Horwood Ltd.; W. Sussex, England). - $tterm = $degrees; - $ttheta = atan2($value, sqrt($tterm)); - $tc = cos($ttheta); - $ts = sin($ttheta); - - if (($degrees % 2) == 1) { - $ti = 3; - $tterm = $tc; - } else { - $ti = 2; - $tterm = 1; - } - - $tsum = $tterm; - while ($ti < $degrees) { - $tterm *= $tc * $tc * ($ti - 1) / $ti; - $tsum += $tterm; - $ti += 2; - } - $tsum *= $ts; - if (($degrees % 2) == 1) { - $tsum = Functions::M_2DIVPI * ($tsum + $ttheta); - } - $tValue = 0.5 * (1 + $tsum); - if ($tails == 1) { - return 1 - abs($tValue); - } - - return 1 - abs((1 - $tValue) - $tValue); - } - - return Functions::VALUE(); + return Statistical\Distributions\StudentT::distribution($value, $degrees, $tails); } /** @@ -2204,6 +2161,11 @@ class Statistical * * Returns the one-tailed probability of the chi-squared distribution. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\StudentT::inverse() + * Use the inverse() method in the Statistical\Distributions\StudentT class instead + * * @param float $probability Probability for the function * @param float $degrees degrees of freedom * @@ -2211,50 +2173,7 @@ class Statistical */ public static function TINV($probability, $degrees) { - $probability = Functions::flattenSingleValue($probability); - $degrees = floor(Functions::flattenSingleValue($degrees)); - - if ((is_numeric($probability)) && (is_numeric($degrees))) { - $xLo = 100; - $xHi = 0; - - $x = $xNew = 1; - $dx = 1; - $i = 0; - - while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $result = self::TDIST($x, $degrees, 2); - $error = $result - $probability; - if ($error == 0.0) { - $dx = 0; - } elseif ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } - // Avoid division by zero - if ($result != 0.0) { - $dx = $error / $result; - $xNew = $x - $dx; - } - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - if ($i == self::MAX_ITERATIONS) { - return Functions::NA(); - } - - return round($x, 12); - } - - return Functions::VALUE(); + return Statistical\Distributions\StudentT::inverse($probability, $degrees); } /** @@ -2421,6 +2340,11 @@ class Statistical * Returns the Weibull distribution. Use this distribution in reliability * analysis, such as calculating a device's mean time to failure. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Weibull::distribution() + * Use the distribution() method in the Statistical\Distributions\Weibull class instead + * * @param float $value * @param float $alpha Alpha Parameter * @param float $beta Beta Parameter @@ -2430,24 +2354,7 @@ class Statistical */ public static function WEIBULL($value, $alpha, $beta, $cumulative) { - $value = Functions::flattenSingleValue($value); - $alpha = Functions::flattenSingleValue($alpha); - $beta = Functions::flattenSingleValue($beta); - - if ((is_numeric($value)) && (is_numeric($alpha)) && (is_numeric($beta))) { - if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 1 - exp(0 - ($value / $beta) ** $alpha); - } - - return ($alpha / $beta ** $alpha) * $value ** ($alpha - 1) * exp(0 - ($value / $beta) ** $alpha); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Weibull::distribution($value, $alpha, $beta, $cumulative); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 2d5e4496..636189b5 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -73,55 +73,13 @@ class ChiSquared return Functions::NAN(); } - return self::calculateInverse($degrees, $probability); - } - - /** - * @return float|string - */ - protected static function calculateInverse(int $degrees, float $probability) - { - $xLo = 100; - $xHi = 0; - - $x = $xNew = 1; - $dx = 1; - $i = 0; - - while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { - // Apply Newton-Raphson step - $result = 1 - (Gamma::incompleteGamma($degrees / 2, $x / 2) + $callback = function ($value) use ($degrees) { + return 1 - (Gamma::incompleteGamma($degrees / 2, $value / 2) / Gamma::gammaValue($degrees / 2)); - $error = $result - $probability; + }; - if ($error == 0.0) { - $dx = 0; - } elseif ($error < 0.0) { - $xLo = $x; - } else { - $xHi = $x; - } + $newtonRaphson = new NewtonRaphson($callback); - // Avoid division by zero - if ($result != 0.0) { - $dx = $error / $result; - $xNew = $x - $dx; - } - - // If the NR fails to converge (which for example may be the - // case if the initial guess is too rough) we apply a bisection - // step to determine a more narrow interval around the root. - if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { - $xNew = ($xLo + $xHi) / 2; - $dx = $xNew - $x; - } - $x = $xNew; - } - - if ($i === self::MAX_ITERATIONS) { - return Functions::NA(); - } - - return $x; + return $newtonRaphson->execute($probability); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php index ae951af3..3f76787d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php @@ -36,8 +36,11 @@ abstract class GammaBase while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { // Apply Newton-Raphson step - $error = self::calculateDistribution($x, $alpha, $beta, true) - $probability; - if ($error < 0.0) { + $result = self::calculateDistribution($x, $alpha, $beta, true); + $error = $result - $probability; + if ($error == 0.0) { + $dx = 0; + } elseif ($error < 0.0) { $xLo = $x; } else { $xHi = $x; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php new file mode 100644 index 00000000..298cdfaf --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -0,0 +1,62 @@ +callback = $callback; + } + + public function execute($probability) + { + $xLo = 100; + $xHi = 0; + + $x = $xNew = 1; + $dx = 1; + $i = 0; + + while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { + // Apply Newton-Raphson step + $result = call_user_func($this->callback, $x); + $error = $result - $probability; + + if ($error == 0.0) { + $dx = 0; + } elseif ($error < 0.0) { + $xLo = $x; + } else { + $xHi = $x; + } + + // Avoid division by zero + if ($result != 0.0) { + $dx = $error / $result; + $xNew = $x - $dx; + } + + // If the NR fails to converge (which for example may be the + // case if the initial guess is too rough) we apply a bisection + // step to determine a more narrow interval around the root. + if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) { + $xNew = ($xLo + $xHi) / 2; + $dx = $xNew - $x; + } + $x = $xNew; + } + + if ($i == self::MAX_ITERATIONS) { + return Functions::NA(); + } + + return $x; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php new file mode 100644 index 00000000..a6d23c6b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php @@ -0,0 +1,127 @@ +getMessage(); + } + + if (($value < 0) || ($degrees < 1) || ($tails < 1) || ($tails > 2)) { + return Functions::NAN(); + } + + return self::calculateDistribution($value, $degrees, $tails); + } + + /** + * TINV. + * + * Returns the one-tailed probability of the chi-squared distribution. + * + * @param mixed (float) $probability Probability for the function + * @param mixed (float) $degrees degrees of freedom + * + * @return float|string The result, or a string containing an error + */ + public static function inverse($probability, $degrees) + { + $probability = Functions::flattenSingleValue($probability); + $degrees = Functions::flattenSingleValue($degrees); + + try { + $probability = self::validateFloat($probability); + $degrees = self::validateInt($degrees); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($probability < 0.0 || $probability > 1.0 || $degrees <= 0) { + return Functions::NAN(); + } + + $callback = function ($value) use ($degrees) { + return self::distribution($value, $degrees, 2); + }; + + $newtonRaphson = new NewtonRaphson($callback); + + return $newtonRaphson->execute($probability); + } + + /** + * @return float|int + */ + private static function calculateDistribution(float $value, int $degrees, int $tails) + { + // tdist, which finds the probability that corresponds to a given value + // of t with k degrees of freedom. This algorithm is translated from a + // pascal function on p81 of "Statistical Computing in Pascal" by D + // Cooke, A H Craven & G M Clark (1985: Edward Arnold (Pubs.) Ltd: + // London). The above Pascal algorithm is itself a translation of the + // fortran algoritm "AS 3" by B E Cooper of the Atlas Computer + // Laboratory as reported in (among other places) "Applied Statistics + // Algorithms", editied by P Griffiths and I D Hill (1985; Ellis + // Horwood Ltd.; W. Sussex, England). + $tterm = $degrees; + $ttheta = atan2($value, sqrt($tterm)); + $tc = cos($ttheta); + $ts = sin($ttheta); + + if (($degrees % 2) === 1) { + $ti = 3; + $tterm = $tc; + } else { + $ti = 2; + $tterm = 1; + } + + $tsum = $tterm; + while ($ti < $degrees) { + $tterm *= $tc * $tc * ($ti - 1) / $ti; + $tsum += $tterm; + $ti += 2; + } + + $tsum *= $ts; + if (($degrees % 2) == 1) { + $tsum = Functions::M_2DIVPI * ($tsum + $ttheta); + } + + $tValue = 0.5 * (1 + $tsum); + if ($tails == 1) { + return 1 - abs($tValue); + } + + return 1 - abs((1 - $tValue) - $tValue); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php new file mode 100644 index 00000000..2064c2e2 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php @@ -0,0 +1,51 @@ +getMessage(); + } + + if (($value < 0) || ($alpha <= 0) || ($beta <= 0)) { + return Functions::NAN(); + } + + if ($cumulative) { + return 1 - exp(0 - ($value / $beta) ** $alpha); + } + + return ($alpha / $beta ** $alpha) * $value ** ($alpha - 1) * exp(0 - ($value / $beta) ** $alpha); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php new file mode 100644 index 00000000..a6a2c97e --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php @@ -0,0 +1,28 @@ + Date: Sat, 27 Mar 2021 18:31:24 +0100 Subject: [PATCH 139/187] Difference in variance calculations between Excel/Gnumeric and Open/LibreOffice (#1959) * Difference in variance calculations between Excel/Gnumeric and Open/LibreOffice * Simplify STDEV() function logic by remembering that STDEV() is simply the square root of VAR(), so we can simply use the VAR() calculaion rather than duplicating the basic logic... and also allow for the differences between Excel/Gnumeric and Open/LibreOffice --- .../Statistical/StandardDeviations.php | 120 +++--------------- .../Calculation/Statistical/VarianceBase.php | 4 +- .../Calculation/Statistical/Variances.php | 2 + .../Functions/Statistical/StDevATest.php | 25 ++++ .../Functions/Statistical/StDevPATest.php | 25 ++++ .../Functions/Statistical/StDevPTest.php | 25 ++++ .../Functions/Statistical/StDevTest.php | 25 ++++ .../Functions/Statistical/VarATest.php | 25 ++++ .../Functions/Statistical/VarPATest.php | 25 ++++ .../Functions/Statistical/VarPTest.php | 25 ++++ .../Functions/Statistical/VarTest.php | 25 ++++ tests/data/Calculation/Statistical/AVEDEV.php | 4 + .../data/Calculation/Statistical/AVERAGE.php | 4 + .../data/Calculation/Statistical/AVERAGEA.php | 8 ++ tests/data/Calculation/Statistical/STDEV.php | 8 ++ tests/data/Calculation/Statistical/STDEVA.php | 8 ++ .../Calculation/Statistical/STDEVA_ODS.php | 20 +++ tests/data/Calculation/Statistical/STDEVP.php | 8 ++ .../data/Calculation/Statistical/STDEVPA.php | 8 ++ .../Calculation/Statistical/STDEVPA_ODS.php | 20 +++ .../Calculation/Statistical/STDEVP_ODS.php | 20 +++ .../Calculation/Statistical/STDEV_ODS.php | 20 +++ tests/data/Calculation/Statistical/VAR.php | 8 ++ tests/data/Calculation/Statistical/VARA.php | 8 ++ .../data/Calculation/Statistical/VARA_ODS.php | 16 +++ tests/data/Calculation/Statistical/VARP.php | 8 ++ tests/data/Calculation/Statistical/VARPA.php | 8 ++ .../Calculation/Statistical/VARPA_ODS.php | 16 +++ .../data/Calculation/Statistical/VARP_ODS.php | 16 +++ .../data/Calculation/Statistical/VAR_ODS.php | 16 +++ 30 files changed, 446 insertions(+), 104 deletions(-) create mode 100644 tests/data/Calculation/Statistical/STDEVA_ODS.php create mode 100644 tests/data/Calculation/Statistical/STDEVPA_ODS.php create mode 100644 tests/data/Calculation/Statistical/STDEVP_ODS.php create mode 100644 tests/data/Calculation/Statistical/STDEV_ODS.php create mode 100644 tests/data/Calculation/Statistical/VARA_ODS.php create mode 100644 tests/data/Calculation/Statistical/VARPA_ODS.php create mode 100644 tests/data/Calculation/Statistical/VARP_ODS.php create mode 100644 tests/data/Calculation/Statistical/VAR_ODS.php diff --git a/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php b/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php index 4f15615c..af271205 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/StandardDeviations.php @@ -2,9 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; - -class StandardDeviations extends VarianceBase +class StandardDeviations { /** * STDEV. @@ -21,34 +19,12 @@ class StandardDeviations extends VarianceBase */ public static function STDEV(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $aMean = Averages::average($aArgs); - - if (!is_string($aMean)) { - $returnValue = 0.0; - $aCount = -1; - - foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) - ) { - $arg = (int) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += ($arg - $aMean) ** 2; - ++$aCount; - } - } - - if ($aCount > 0) { - return sqrt($returnValue / $aCount); - } + $result = Variances::VAR(...$args); + if (!is_numeric($result)) { + return $result; } - return Functions::DIV0(); + return sqrt((float) $result); } /** @@ -65,32 +41,12 @@ class StandardDeviations extends VarianceBase */ public static function STDEVA(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $aMean = Averages::averageA($aArgs); - - if (!is_string($aMean)) { - $returnValue = 0.0; - $aCount = -1; - - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && (!Functions::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - $arg = self::datatypeAdjustmentAllowStrings($arg); - $returnValue += ($arg - $aMean) ** 2; - ++$aCount; - } - } - } - - if ($aCount > 0) { - return sqrt($returnValue / $aCount); - } + $result = Variances::VARA(...$args); + if (!is_numeric($result)) { + return $result; } - return Functions::DIV0(); + return sqrt((float) $result); } /** @@ -107,34 +63,12 @@ class StandardDeviations extends VarianceBase */ public static function STDEVP(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $aMean = Averages::average($aArgs); - - if (!is_string($aMean)) { - $returnValue = 0.0; - $aCount = 0; - - foreach ($aArgs as $k => $arg) { - if ( - (is_bool($arg)) && - ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) - ) { - $arg = (int) $arg; - } - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += ($arg - $aMean) ** 2; - ++$aCount; - } - } - - if ($aCount > 0) { - return sqrt($returnValue / $aCount); - } + $result = Variances::VARP(...$args); + if (!is_numeric($result)) { + return $result; } - return Functions::DIV0(); + return sqrt((float) $result); } /** @@ -151,31 +85,11 @@ class StandardDeviations extends VarianceBase */ public static function STDEVPA(...$args) { - $aArgs = Functions::flattenArrayIndexed($args); - - $aMean = Averages::averageA($aArgs); - - if (!is_string($aMean)) { - $returnValue = 0.0; - $aCount = 0; - - foreach ($aArgs as $k => $arg) { - if ((is_bool($arg)) && (!Functions::isMatrixValue($k))) { - } else { - // Is it a numeric value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { - $arg = self::datatypeAdjustmentAllowStrings($arg); - $returnValue += ($arg - $aMean) ** 2; - ++$aCount; - } - } - } - - if ($aCount > 0) { - return sqrt($returnValue / $aCount); - } + $result = Variances::VARPA(...$args); + if (!is_numeric($result)) { + return $result; } - return Functions::DIV0(); + return sqrt((float) $result); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php b/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php index 9762ec84..e5334671 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; + abstract class VarianceBase { protected static function datatypeAdjustmentAllowStrings($value) @@ -17,7 +19,7 @@ abstract class VarianceBase protected static function datatypeAdjustmentBooleans($value) { - if (is_bool($value)) { + if (is_bool($value) && (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE)) { return (int) $value; } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Variances.php b/src/PhpSpreadsheet/Calculation/Statistical/Variances.php index 78b08da9..ac9c3320 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Variances.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Variances.php @@ -29,6 +29,7 @@ class Variances extends VarianceBase $aCount = 0; foreach ($aArgs as $arg) { $arg = self::datatypeAdjustmentBooleans($arg); + // Is it a numeric value? if ((is_numeric($arg)) && (!is_string($arg))) { $summerA += ($arg * $arg); @@ -117,6 +118,7 @@ class Variances extends VarianceBase $aCount = 0; foreach ($aArgs as $arg) { $arg = self::datatypeAdjustmentBooleans($arg); + // Is it a numeric value? if ((is_numeric($arg)) && (!is_string($arg))) { $summerA += ($arg * $arg); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php index 9115db46..79e4482a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class StDevATest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerSTDEVA * @@ -23,4 +29,23 @@ class StDevATest extends TestCase { return require 'tests/data/Calculation/Statistical/STDEVA.php'; } + + /** + * @dataProvider providerOdsSTDEVA + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsSTDEVA($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::STDEVA($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsSTDEVA() + { + return require 'tests/data/Calculation/Statistical/STDEVA_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php index 9d8921cc..b004e5b0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class StDevPATest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerSTDEVPA * @@ -23,4 +29,23 @@ class StDevPATest extends TestCase { return require 'tests/data/Calculation/Statistical/STDEVPA.php'; } + + /** + * @dataProvider providerOdsSTDEVPA + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsSTDEVPA($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::STDEVPA($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsSTDEVPA() + { + return require 'tests/data/Calculation/Statistical/STDEVPA_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php index 47b058b3..7e45ec51 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class StDevPTest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerSTDEVP * @@ -23,4 +29,23 @@ class StDevPTest extends TestCase { return require 'tests/data/Calculation/Statistical/STDEVP.php'; } + + /** + * @dataProvider providerOdsSTDEVP + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsSTDEVP($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::STDEVP($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsSTDEVP() + { + return require 'tests/data/Calculation/Statistical/STDEVP_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php index 6a96fa2f..bc59869d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class StDevTest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerSTDEV * @@ -23,4 +29,23 @@ class StDevTest extends TestCase { return require 'tests/data/Calculation/Statistical/STDEV.php'; } + + /** + * @dataProvider providerOdsSTDEV + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsSTDEV($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::STDEV($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsSTDEV() + { + return require 'tests/data/Calculation/Statistical/STDEV_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php index 1b8b676f..8d664af4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class VarATest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerVARA * @@ -23,4 +29,23 @@ class VarATest extends TestCase { return require 'tests/data/Calculation/Statistical/VARA.php'; } + + /** + * @dataProvider providerOdsVARA + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsVARA($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::VARA($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsVARA() + { + return require 'tests/data/Calculation/Statistical/VARA_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php index ee0cfee6..8240b5cf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class VarPATest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerVARPA * @@ -23,4 +29,23 @@ class VarPATest extends TestCase { return require 'tests/data/Calculation/Statistical/VARPA.php'; } + + /** + * @dataProvider providerOdsVARPA + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsVARPA($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::VARPA($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsVARPA() + { + return require 'tests/data/Calculation/Statistical/VARPA_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php index fe3af037..bbc5239c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class VarPTest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerVARP * @@ -23,4 +29,23 @@ class VarPTest extends TestCase { return require 'tests/data/Calculation/Statistical/VARP.php'; } + + /** + * @dataProvider providerOdsVARP + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsVARP($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::VARP($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsVARP() + { + return require 'tests/data/Calculation/Statistical/VARP_ODS.php'; + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php index aa25f5cc..15aa98a0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php @@ -2,11 +2,17 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; class VarTest extends TestCase { + protected function tearDown(): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); + } + /** * @dataProvider providerVAR * @@ -23,4 +29,23 @@ class VarTest extends TestCase { return require 'tests/data/Calculation/Statistical/VAR.php'; } + + /** + * @dataProvider providerOdsVAR + * + * @param mixed $expectedResult + * @param mixed $values + */ + public function testOdsVAR($expectedResult, $values): void + { + Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE); + + $result = Statistical::VARFunc($values); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + } + + public function providerOdsVAR() + { + return require 'tests/data/Calculation/Statistical/VAR_ODS.php'; + } } diff --git a/tests/data/Calculation/Statistical/AVEDEV.php b/tests/data/Calculation/Statistical/AVEDEV.php index 89713592..b2fa9a14 100644 --- a/tests/data/Calculation/Statistical/AVEDEV.php +++ b/tests/data/Calculation/Statistical/AVEDEV.php @@ -42,4 +42,8 @@ return [ '#VALUE!', [1, '2', 3.4, true, 5, null, 6.7, 'STRING', ''], ], + [ + '#NUM!', + [], + ], ]; diff --git a/tests/data/Calculation/Statistical/AVERAGE.php b/tests/data/Calculation/Statistical/AVERAGE.php index d435e89b..33283cdd 100644 --- a/tests/data/Calculation/Statistical/AVERAGE.php +++ b/tests/data/Calculation/Statistical/AVERAGE.php @@ -50,4 +50,8 @@ return [ '#VALUE!', [1, '2', 3.4, true, 5, null, 6.7, 'STRING', ''], ], + [ + '#DIV/0!', + [], + ], ]; diff --git a/tests/data/Calculation/Statistical/AVERAGEA.php b/tests/data/Calculation/Statistical/AVERAGEA.php index de6bf1b4..14781550 100644 --- a/tests/data/Calculation/Statistical/AVERAGEA.php +++ b/tests/data/Calculation/Statistical/AVERAGEA.php @@ -21,4 +21,12 @@ return [ 0.5, [true, false], ], + [ + 0.666666666667, + [true, false, 1], + ], + [ + '#DIV/0!', + [], + ], ]; diff --git a/tests/data/Calculation/Statistical/STDEV.php b/tests/data/Calculation/Statistical/STDEV.php index 846f8c71..30d9dc3b 100644 --- a/tests/data/Calculation/Statistical/STDEV.php +++ b/tests/data/Calculation/Statistical/STDEV.php @@ -9,4 +9,12 @@ return [ '#DIV/0!', ['A', 'B', 'C'], ], + [ + '#DIV/0!', + [true, false], + ], + [ + '#DIV/0!', + [true, false, 1], + ], ]; diff --git a/tests/data/Calculation/Statistical/STDEVA.php b/tests/data/Calculation/Statistical/STDEVA.php index 9fd45d65..13cecc61 100644 --- a/tests/data/Calculation/Statistical/STDEVA.php +++ b/tests/data/Calculation/Statistical/STDEVA.php @@ -9,4 +9,12 @@ return [ '#DIV/0!', [], ], + [ + 0.707106781187, + [true, false], + ], + [ + 0.577350269190, + [true, false, 1], + ], ]; diff --git a/tests/data/Calculation/Statistical/STDEVA_ODS.php b/tests/data/Calculation/Statistical/STDEVA_ODS.php new file mode 100644 index 00000000..559798e4 --- /dev/null +++ b/tests/data/Calculation/Statistical/STDEVA_ODS.php @@ -0,0 +1,20 @@ + Date: Sat, 27 Mar 2021 22:04:05 +0100 Subject: [PATCH 140/187] Implementation of the CHITEST() statistical function (#1960) * Implementation of the CHITEST() statistical function * A couple of additional edge case tests (rows = 1, columns = 1) --- CHANGELOG.md | 1 + .../Calculation/Calculation.php | 4 +- .../Statistical/Distributions/ChiSquared.php | 41 +++++++++++++++++++ .../Functions/Statistical/ChiTestTest.php | 27 ++++++++++++ .../data/Calculation/Statistical/CHITEST.php | 39 ++++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php create mode 100644 tests/data/Calculation/Statistical/CHITEST.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b46323f..d6d252d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added +- Implemented the CHITEST() Statistical function. - Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) ### Changed diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 6e98fcb0..62524c37 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -518,12 +518,12 @@ class Calculation ], 'CHITEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'test'], 'argumentCount' => '2', ], 'CHISQ.TEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'test'], 'argumentCount' => '2', ], 'CHOOSE' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 636189b5..dfd090de 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -82,4 +82,45 @@ class ChiSquared return $newtonRaphson->execute($probability); } + + public static function test($actual, $expected) + { + $rows = count($actual); + $actual = Functions::flattenArray($actual); + $expected = Functions::flattenArray($expected); + $columns = count($actual) / $rows; + + $countActuals = count($actual); + $countExpected = count($expected); + if ($countActuals !== $countExpected || $countActuals === 1) { + return Functions::NAN(); + } + + $result = 0.0; + for ($i = 0; $i < $countActuals; ++$i) { + if ($expected[$i] == 0.0) { + return Functions::DIV0(); + } elseif ($expected[$i] < 0.0) { + return Functions::NAN(); + } + $result += (($actual[$i] - $expected[$i]) ** 2) / $expected[$i]; + } + + $degrees = self::degrees($rows, $columns); + + $result = self::distribution($result, $degrees); + + return $result; + } + + protected static function degrees(int $rows, int $columns): int + { + if ($rows === 1) { + return $columns - 1; + } elseif ($columns === 1) { + return $rows - 1; + } + + return ($columns - 1) * ($rows - 1); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php new file mode 100644 index 00000000..5f9f361f --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php @@ -0,0 +1,27 @@ + Date: Sun, 28 Mar 2021 13:48:34 +0900 Subject: [PATCH 141/187] Update PHP deps Simplify our constraints thanks to PHPUnit 8.5 that supports PHP 8+ --- .github/workflows/main.yml | 2 +- composer.json | 32 +- composer.lock | 1097 +++++++++++++----------------------- 3 files changed, 414 insertions(+), 717 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 707a9a3f..ce38f646 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -43,7 +43,7 @@ jobs: - name: Delete composer lock file id: composer-lock - if: ${{ matrix.php-version == '8.0' || matrix.php-version == '8.1' }} + if: ${{ matrix.php-version == '8.1' }} run: | rm composer.lock echo "::set-output name=flags::--ignore-platform-reqs" diff --git a/composer.json b/composer.json index 483c3828..3b4ed556 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,19 @@ { "name": "phpoffice/phpspreadsheet", "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", - "keywords": ["PHP", "OpenXML", "Excel", "xlsx", "xls", "ods", "gnumeric", "spreadsheet"], + "keywords": [ + "PHP", + "OpenXML", + "Excel", + "xlsx", + "xls", + "ods", + "gnumeric", + "spreadsheet" + ], + "config": { + "sort-packages": true + }, "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", "type": "library", "license": "MIT", @@ -39,35 +51,35 @@ ] }, "require": { - "php": "^7.2||^8.0", + "php": "^7.2 || ^8.0", + "ext-simplexml": "*", "ext-ctype": "*", "ext-dom": "*", + "ext-fileinfo": "*", "ext-gd": "*", "ext-iconv": "*", - "ext-fileinfo": "*", "ext-libxml": "*", "ext-mbstring": "*", - "ext-SimpleXML": "*", "ext-xml": "*", "ext-xmlreader": "*", "ext-xmlwriter": "*", "ext-zip": "*", "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.13", "maennchen/zipstream-php": "^2.1", - "markbaker/complex": "^1.5||^2.0", - "markbaker/matrix": "^1.2||^2.0", - "psr/simple-cache": "^1.0", + "markbaker/complex": "^2.0", + "markbaker/matrix": "^2.0", "psr/http-client": "^1.0", "psr/http-factory": "^1.0", - "ezyang/htmlpurifier": "^4.13" + "psr/simple-cache": "^1.0" }, "require-dev": { - "dompdf/dompdf": "^0.8.5", + "dompdf/dompdf": "^1.0", "friendsofphp/php-cs-fixer": "^2.18", "jpgraph/jpgraph": "^4.0", "mpdf/mpdf": "^8.0", "phpcompatibility/php-compatibility": "^9.3", - "phpunit/phpunit": "^8.5||^9.3", + "phpunit/phpunit": "^8.5", "squizlabs/php_codesniffer": "^3.5", "tecnickcom/tcpdf": "^6.3" }, diff --git a/composer.lock b/composer.lock index bbb9ff7e..3f6efb00 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8a567f9030fc836c175557d0430f1057", + "content-hash": "6c8f34baf3385a533fade30a9a9ad6f1", "packages": [ { "name": "ezyang/htmlpurifier", @@ -577,16 +577,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13" + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", - "reference": "f377a3dd1fde44d37b9831d68dc8dea3ffd28e13", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/5232de97ee3b75b0360528dae24e73db49566ab1", + "reference": "5232de97ee3b75b0360528dae24e73db49566ab1", "shasum": "" }, "require": { @@ -637,7 +637,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.22.1" }, "funding": [ { @@ -653,7 +653,7 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-01-22T09:19:47+00:00" } ], "packages-dev": [ @@ -740,16 +740,16 @@ }, { "name": "composer/xdebug-handler", - "version": "1.4.5", + "version": "1.4.6", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "f28d44c286812c714741478d968104c5e604a1d4" + "reference": "f27e06cd9675801df441b3656569b328e04aa37c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f28d44c286812c714741478d968104c5e604a1d4", - "reference": "f28d44c286812c714741478d968104c5e604a1d4", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/f27e06cd9675801df441b3656569b328e04aa37c", + "reference": "f27e06cd9675801df441b3656569b328e04aa37c", "shasum": "" }, "require": { @@ -757,7 +757,8 @@ "psr/log": "^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" }, "type": "library", "autoload": { @@ -783,7 +784,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/1.4.5" + "source": "https://github.com/composer/xdebug-handler/tree/1.4.6" }, "funding": [ { @@ -799,20 +800,20 @@ "type": "tidelift" } ], - "time": "2020-11-13T08:04:11+00:00" + "time": "2021-03-25T17:01:18+00:00" }, { "name": "doctrine/annotations", - "version": "1.11.1", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad" + "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/ce77a7ba1770462cd705a91a151b6c3746f9c6ad", - "reference": "ce77a7ba1770462cd705a91a151b6c3746f9c6ad", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/b17c5014ef81d212ac539f07a1001832df1b6d3b", + "reference": "b17c5014ef81d212ac539f07a1001832df1b6d3b", "shasum": "" }, "require": { @@ -827,11 +828,6 @@ "phpunit/phpunit": "^7.5 || ^9.1.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, "autoload": { "psr-4": { "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" @@ -872,9 +868,9 @@ ], "support": { "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.11.1" + "source": "https://github.com/doctrine/annotations/tree/1.12.1" }, - "time": "2020-10-26T10:28:16+00:00" + "time": "2021-02-21T21:00:45+00:00" }, { "name": "doctrine/instantiator", @@ -1027,16 +1023,16 @@ }, { "name": "dompdf/dompdf", - "version": "v0.8.6", + "version": "v1.0.2", "source": { "type": "git", "url": "https://github.com/dompdf/dompdf.git", - "reference": "db91d81866c69a42dad1d2926f61515a1e3f42c5" + "reference": "8768448244967a46d6e67b891d30878e0e15d25c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/db91d81866c69a42dad1d2926f61515a1e3f42c5", - "reference": "db91d81866c69a42dad1d2926f61515a1e3f42c5", + "url": "https://api.github.com/repos/dompdf/dompdf/zipball/8768448244967a46d6e67b891d30878e0e15d25c", + "reference": "8768448244967a46d6e67b891d30878e0e15d25c", "shasum": "" }, "require": { @@ -1044,11 +1040,11 @@ "ext-mbstring": "*", "phenx/php-font-lib": "^0.5.2", "phenx/php-svg-lib": "^0.3.3", - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5", + "phpunit/phpunit": "^7.5 || ^8 || ^9", "squizlabs/php_codesniffer": "^3.5" }, "suggest": { @@ -1093,22 +1089,22 @@ "homepage": "https://github.com/dompdf/dompdf", "support": { "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/master" + "source": "https://github.com/dompdf/dompdf/tree/v1.0.2" }, - "time": "2020-08-30T22:54:22+00:00" + "time": "2021-01-08T14:18:52+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v2.18.2", + "version": "v2.18.4", "source": { "type": "git", "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "18f8c9d184ba777380794a389fabc179896ba913" + "reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/18f8c9d184ba777380794a389fabc179896ba913", - "reference": "18f8c9d184ba777380794a389fabc179896ba913", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/06f764e3cb6d60822d8f5135205f9d32b5508a31", + "reference": "06f764e3cb6d60822d8f5135205f9d32b5508a31", "shasum": "" }, "require": { @@ -1170,6 +1166,7 @@ "tests/Test/IntegrationCaseFactoryInterface.php", "tests/Test/InternalIntegrationCaseFactory.php", "tests/Test/IsIdenticalConstraint.php", + "tests/Test/TokensWithObservedTransformers.php", "tests/TestCase.php" ] }, @@ -1190,7 +1187,7 @@ "description": "A tool to automatically fix PHP code style", "support": { "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.2" + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v2.18.4" }, "funding": [ { @@ -1198,7 +1195,7 @@ "type": "github" } ], - "time": "2021-01-26T00:22:21+00:00" + "time": "2021-03-20T14:52:33+00:00" }, { "name": "jpgraph/jpgraph", @@ -1378,62 +1375,6 @@ ], "time": "2020-11-13T09:40:50+00:00" }, - { - "name": "nikic/php-parser", - "version": "v4.10.4", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "reference": "c6d052fc58cb876152f89f532b95a8d7907e7f0e", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.10.4" - }, - "time": "2020-12-20T10:01:03+00:00" - }, { "name": "paragonie/random_compat", "version": "v9.99.100", @@ -1546,16 +1487,16 @@ }, { "name": "phar-io/version", - "version": "3.0.4", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/phar-io/version.git", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451" + "reference": "bae7c545bef187884426f042434e561ab1ddb182" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/e4782611070e50613683d2b9a57730e9a3ba5451", - "reference": "e4782611070e50613683d2b9a57730e9a3ba5451", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", "shasum": "" }, "require": { @@ -1591,9 +1532,9 @@ "description": "Library for handling version information and constraints", "support": { "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.0.4" + "source": "https://github.com/phar-io/version/tree/3.1.0" }, - "time": "2020-12-13T23:18:30+00:00" + "time": "2021-02-23T14:00:09+00:00" }, { "name": "phenx/php-font-lib", @@ -1957,16 +1898,16 @@ }, { "name": "phpspec/prophecy", - "version": "1.12.2", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "245710e971a030f42e08f4912863805570f23d39" + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", - "reference": "245710e971a030f42e08f4912863805570f23d39", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", "shasum": "" }, "require": { @@ -2018,50 +1959,46 @@ ], "support": { "issues": "https://github.com/phpspec/prophecy/issues", - "source": "https://github.com/phpspec/prophecy/tree/1.12.2" + "source": "https://github.com/phpspec/prophecy/tree/1.13.0" }, - "time": "2020-12-19T10:15:11+00:00" + "time": "2021-03-17T13:42:18+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.5", + "version": "7.0.14", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1" + "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f3e026641cc91909d421802dd3ac7827ebfd97e1", - "reference": "f3e026641cc91909d421802dd3ac7827ebfd97e1", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bb7c9a210c72e4709cdde67f8b7362f672f2225c", + "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c", "shasum": "" }, "require": { "ext-dom": "*", - "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.10.2", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "php": ">=7.2", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.1.1 || ^4.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^4.2.2", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.2.2" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-xdebug": "^2.7.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-master": "7.0-dev" } }, "autoload": { @@ -2089,7 +2026,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.5" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.14" }, "funding": [ { @@ -2097,32 +2034,32 @@ "type": "github" } ], - "time": "2020-11-28T06:44:49+00:00" + "time": "2020-12-02T13:39:03+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "3.0.5", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4b49fb70f067272b659ef0174ff9ca40fdaa6357", + "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -2149,7 +2086,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.3" }, "funding": [ { @@ -2157,97 +2094,26 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" + "time": "2020-11-30T08:25:21+00:00" }, { "name": "phpunit/php-text-template", - "version": "2.0.4", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" + "php": ">=5.3.3" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, "autoload": { "classmap": [ "src/" @@ -2271,40 +2137,34 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", - "version": "5.0.3", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "2.1-dev" } }, "autoload": { @@ -2330,7 +2190,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" }, "funding": [ { @@ -2338,20 +2198,80 @@ "type": "github" } ], - "time": "2020-10-26T13:16:10+00:00" + "time": "2020-11-30T08:20:02+00:00" }, { - "name": "phpunit/phpunit", - "version": "9.5.1", + "name": "phpunit/php-token-stream", + "version": "3.1.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360" + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "472b687829041c24b25f475e14c2f38a09edf1c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e7bdf4085de85a825f4424eae52c99a1cec2f360", - "reference": "e7bdf4085de85a825f4424eae52c99a1cec2f360", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2", + "reference": "472b687829041c24b25f475e14c2f38a09edf1c2", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-11-30T08:38:46+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "8.5.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "038d4196d8e8cb405cd5e82cedfe413ad6eef9ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/038d4196d8e8cb405cd5e82cedfe413ad6eef9ef", + "reference": "038d4196d8e8cb405cd5e82cedfe413ad6eef9ef", "shasum": "" }, "require": { @@ -2362,35 +2282,32 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", + "myclabs/deep-copy": "^1.10.0", "phar-io/manifest": "^2.0.1", "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpspec/prophecy": "^1.12.1", - "phpunit/php-code-coverage": "^9.2.3", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.5", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.3", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^2.3", - "sebastian/version": "^3.0.2" + "php": ">=7.2", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^7.0.12", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.3", + "sebastian/exporter": "^3.1.2", + "sebastian/global-state": "^3.0.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", + "sebastian/version": "^2.0.1" }, "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0.1" + "ext-pdo": "*" }, "suggest": { "ext-soap": "*", - "ext-xdebug": "*" + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0.0" }, "bin": [ "phpunit" @@ -2398,15 +2315,12 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "8.5-dev" } }, "autoload": { "classmap": [ "src/" - ], - "files": [ - "src/Framework/Assert/Functions.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2429,7 +2343,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.1" + "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.15" }, "funding": [ { @@ -2441,31 +2355,26 @@ "type": "github" } ], - "time": "2021-01-17T07:42:25+00:00" + "time": "2021-03-17T07:27:54+00:00" }, { "name": "psr/container", - "version": "1.0.0", + "version": "1.1.1", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.2.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -2478,7 +2387,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -2492,9 +2401,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/container/tree/1.1.1" }, - "time": "2017-02-14T16:28:37+00:00" + "time": "2021-03-05T17:36:06+00:00" }, { "name": "psr/event-dispatcher", @@ -2645,142 +2554,30 @@ }, "time": "2020-06-01T09:10:00+00:00" }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, { "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=5.6" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { @@ -2802,7 +2599,7 @@ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "support": { "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" }, "funding": [ { @@ -2810,34 +2607,34 @@ "type": "github" } ], - "time": "2020-09-28T05:30:19+00:00" + "time": "2020-11-30T08:15:22+00:00" }, { "name": "sebastian/comparator", - "version": "4.0.6", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382" + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/55f4261989e546dc112258c7a75935a81a7ce382", - "reference": "55f4261989e546dc112258c7a75935a81a7ce382", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" + "php": ">=7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2876,7 +2673,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.6" + "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.3" }, "funding": [ { @@ -2884,90 +2681,33 @@ "type": "github" } ], - "time": "2020-10-26T15:49:45+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.7", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2020-11-30T08:04:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -2999,7 +2739,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" }, "funding": [ { @@ -3007,27 +2747,27 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2020-11-30T07:59:04+00:00" }, { "name": "sebastian/environment", - "version": "5.1.3", + "version": "4.2.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^7.5" }, "suggest": { "ext-posix": "*" @@ -3035,7 +2775,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -3062,7 +2802,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.3" + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" }, "funding": [ { @@ -3070,34 +2810,34 @@ "type": "github" } ], - "time": "2020-09-28T05:52:38+00:00" + "time": "2020-11-30T07:53:42+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.3", + "version": "3.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" + "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e", + "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" + "php": ">=7.0", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -3139,7 +2879,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.3" + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.3" }, "funding": [ { @@ -3147,30 +2887,30 @@ "type": "github" } ], - "time": "2020-09-28T05:24:23+00:00" + "time": "2020-11-30T07:47:53+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.2", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455" + "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/a90ccbddffa067b51f574dea6eb25d5680839455", - "reference": "a90ccbddffa067b51f574dea6eb25d5680839455", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/474fb9edb7ab891665d3bfc6317f42a0a150454b", + "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-dom": "*", - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.0" }, "suggest": { "ext-uopz": "*" @@ -3178,7 +2918,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -3203,7 +2943,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.2" + "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.1" }, "funding": [ { @@ -3211,91 +2951,34 @@ "type": "github" } ], - "time": "2020-10-26T15:55:19+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.6", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2020-11-30T07:43:24+00:00" }, { "name": "sebastian/object-enumerator", - "version": "4.0.4", + "version": "3.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", "shasum": "" }, "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -3317,7 +3000,7 @@ "homepage": "https://github.com/sebastianbergmann/object-enumerator/", "support": { "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" }, "funding": [ { @@ -3325,32 +3008,32 @@ "type": "github" } ], - "time": "2020-10-26T13:12:34+00:00" + "time": "2020-11-30T07:40:27+00:00" }, { "name": "sebastian/object-reflector", - "version": "2.0.4", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -3372,7 +3055,7 @@ "homepage": "https://github.com/sebastianbergmann/object-reflector/", "support": { "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" }, "funding": [ { @@ -3380,32 +3063,32 @@ "type": "github" } ], - "time": "2020-10-26T13:14:26+00:00" + "time": "2020-11-30T07:37:18+00:00" }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -3435,7 +3118,7 @@ "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" }, "funding": [ { @@ -3443,32 +3126,29 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2020-11-30T07:34:24+00:00" }, { "name": "sebastian/resource-operations", - "version": "3.0.3", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -3490,7 +3170,7 @@ "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" }, "funding": [ { @@ -3498,32 +3178,32 @@ "type": "github" } ], - "time": "2020-09-28T06:45:17+00:00" + "time": "2020-11-30T07:30:19+00:00" }, { "name": "sebastian/type", - "version": "2.3.1", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2" + "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/81cd61ab7bbf2de744aba0ea61fae32f721df3d2", - "reference": "81cd61ab7bbf2de744aba0ea61fae32f721df3d2", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=7.2" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^8.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -3546,7 +3226,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/2.3.1" + "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" }, "funding": [ { @@ -3554,29 +3234,29 @@ "type": "github" } ], - "time": "2020-10-26T13:18:59+00:00" + "time": "2020-11-30T07:25:11+00:00" }, { "name": "sebastian/version", - "version": "3.0.2", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, "require": { - "php": ">=7.3" + "php": ">=5.6" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -3599,28 +3279,22 @@ "homepage": "https://github.com/sebastianbergmann/version", "support": { "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + "source": "https://github.com/sebastianbergmann/version/tree/master" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "setasign/fpdi", - "version": "v2.3.5", + "version": "v2.3.6", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "f2246c8669bd25834f5c264425eb0e250d7a9312" + "reference": "6231e315f73e4f62d72b73f3d6d78ff0eed93c31" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/f2246c8669bd25834f5c264425eb0e250d7a9312", - "reference": "f2246c8669bd25834f5c264425eb0e250d7a9312", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/6231e315f73e4f62d72b73f3d6d78ff0eed93c31", + "reference": "6231e315f73e4f62d72b73f3d6d78ff0eed93c31", "shasum": "" }, "require": { @@ -3671,7 +3345,7 @@ ], "support": { "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.3.5" + "source": "https://github.com/Setasign/FPDI/tree/v2.3.6" }, "funding": [ { @@ -3679,7 +3353,7 @@ "type": "tidelift" } ], - "time": "2020-12-03T13:40:03+00:00" + "time": "2021-02-11T11:37:01+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -3739,16 +3413,16 @@ }, { "name": "symfony/console", - "version": "v5.2.2", + "version": "v5.2.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a" + "reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/d62ec79478b55036f65e2602e282822b8eaaff0a", - "reference": "d62ec79478b55036f65e2602e282822b8eaaff0a", + "url": "https://api.github.com/repos/symfony/console/zipball/938ebbadae1b0a9c9d1ec313f87f9708609f1b79", + "reference": "938ebbadae1b0a9c9d1ec313f87f9708609f1b79", "shasum": "" }, "require": { @@ -3816,7 +3490,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.2.2" + "source": "https://github.com/symfony/console/tree/v5.2.5" }, "funding": [ { @@ -3832,7 +3506,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:15:41+00:00" + "time": "2021-03-06T13:42:15+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3903,16 +3577,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "4f9760f8074978ad82e2ce854dff79a71fe45367" + "reference": "d08d6ec121a425897951900ab692b612a61d6240" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/4f9760f8074978ad82e2ce854dff79a71fe45367", - "reference": "4f9760f8074978ad82e2ce854dff79a71fe45367", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d08d6ec121a425897951900ab692b612a61d6240", + "reference": "d08d6ec121a425897951900ab692b612a61d6240", "shasum": "" }, "require": { @@ -3968,7 +3642,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.2" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.2.4" }, "funding": [ { @@ -3984,7 +3658,7 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:36:42+00:00" + "time": "2021-02-18T17:12:37+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -4067,16 +3741,16 @@ }, { "name": "symfony/filesystem", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038" + "reference": "710d364200997a5afde34d9fe57bd52f3cc1e108" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/262d033b57c73e8b59cd6e68a45c528318b15038", - "reference": "262d033b57c73e8b59cd6e68a45c528318b15038", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/710d364200997a5afde34d9fe57bd52f3cc1e108", + "reference": "710d364200997a5afde34d9fe57bd52f3cc1e108", "shasum": "" }, "require": { @@ -4109,7 +3783,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.2.2" + "source": "https://github.com/symfony/filesystem/tree/v5.2.4" }, "funding": [ { @@ -4125,20 +3799,20 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2021-02-12T10:38:38+00:00" }, { "name": "symfony/finder", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e" + "reference": "0d639a0943822626290d169965804f79400e6a04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/196f45723b5e618bf0e23b97e96d11652696ea9e", - "reference": "196f45723b5e618bf0e23b97e96d11652696ea9e", + "url": "https://api.github.com/repos/symfony/finder/zipball/0d639a0943822626290d169965804f79400e6a04", + "reference": "0d639a0943822626290d169965804f79400e6a04", "shasum": "" }, "require": { @@ -4170,7 +3844,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.2.2" + "source": "https://github.com/symfony/finder/tree/v5.2.4" }, "funding": [ { @@ -4186,11 +3860,11 @@ "type": "tidelift" } ], - "time": "2021-01-27T10:01:46+00:00" + "time": "2021-02-15T18:55:04+00:00" }, { "name": "symfony/options-resolver", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", @@ -4239,7 +3913,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.2.2" + "source": "https://github.com/symfony/options-resolver/tree/v5.2.4" }, "funding": [ { @@ -4259,7 +3933,7 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -4318,7 +3992,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.22.1" }, "funding": [ { @@ -4338,16 +4012,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "267a9adeb8ecb8071040a740930e077cdfb987af" + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/267a9adeb8ecb8071040a740930e077cdfb987af", - "reference": "267a9adeb8ecb8071040a740930e077cdfb987af", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/5601e09b69f26c1828b13b6bb87cb07cddba3170", + "reference": "5601e09b69f26c1828b13b6bb87cb07cddba3170", "shasum": "" }, "require": { @@ -4399,7 +4073,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.22.1" }, "funding": [ { @@ -4415,20 +4089,20 @@ "type": "tidelift" } ], - "time": "2021-01-07T16:49:33+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba" + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/6e971c891537eb617a00bb07a43d182a6915faba", - "reference": "6e971c891537eb617a00bb07a43d182a6915faba", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/43a0283138253ed1d48d352ab6d0bdb3f809f248", + "reference": "43a0283138253ed1d48d352ab6d0bdb3f809f248", "shasum": "" }, "require": { @@ -4483,7 +4157,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.22.1" }, "funding": [ { @@ -4499,7 +4173,7 @@ "type": "tidelift" } ], - "time": "2021-01-07T17:09:11+00:00" + "time": "2021-01-22T09:19:47+00:00" }, { "name": "symfony/polyfill-php70", @@ -4571,7 +4245,7 @@ }, { "name": "symfony/polyfill-php72", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php72.git", @@ -4627,7 +4301,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php72/tree/v1.22.1" }, "funding": [ { @@ -4647,7 +4321,7 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", @@ -4706,7 +4380,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.22.1" }, "funding": [ { @@ -4726,7 +4400,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.22.0", + "version": "v1.22.1", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -4789,7 +4463,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.22.1" }, "funding": [ { @@ -4809,7 +4483,7 @@ }, { "name": "symfony/process", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", @@ -4851,7 +4525,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.2.2" + "source": "https://github.com/symfony/process/tree/v5.2.4" }, "funding": [ { @@ -4950,7 +4624,7 @@ }, { "name": "symfony/stopwatch", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", @@ -4992,7 +4666,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.2.2" + "source": "https://github.com/symfony/stopwatch/tree/v5.2.4" }, "funding": [ { @@ -5012,16 +4686,16 @@ }, { "name": "symfony/string", - "version": "v5.2.2", + "version": "v5.2.4", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "c95468897f408dd0aca2ff582074423dd0455122" + "reference": "4e78d7d47061fa183639927ec40d607973699609" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/c95468897f408dd0aca2ff582074423dd0455122", - "reference": "c95468897f408dd0aca2ff582074423dd0455122", + "url": "https://api.github.com/repos/symfony/string/zipball/4e78d7d47061fa183639927ec40d607973699609", + "reference": "4e78d7d47061fa183639927ec40d607973699609", "shasum": "" }, "require": { @@ -5075,7 +4749,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.2.2" + "source": "https://github.com/symfony/string/tree/v5.2.4" }, "funding": [ { @@ -5091,20 +4765,20 @@ "type": "tidelift" } ], - "time": "2021-01-25T15:14:59+00:00" + "time": "2021-02-16T10:20:28+00:00" }, { "name": "tecnickcom/tcpdf", - "version": "6.3.5", + "version": "6.4.1", "source": { "type": "git", "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549" + "reference": "5ba838befdb37ef06a16d9f716f35eb03cb1b329" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/19a535eaa7fb1c1cac499109deeb1a7a201b4549", - "reference": "19a535eaa7fb1c1cac499109deeb1a7a201b4549", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/5ba838befdb37ef06a16d9f716f35eb03cb1b329", + "reference": "5ba838befdb37ef06a16d9f716f35eb03cb1b329", "shasum": "" }, "require": { @@ -5155,9 +4829,15 @@ ], "support": { "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.3.5" + "source": "https://github.com/tecnickcom/TCPDF/tree/6.4.1" }, - "time": "2020-02-14T14:20:12+00:00" + "funding": [ + { + "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project", + "type": "custom" + } + ], + "time": "2021-03-27T16:00:33+00:00" }, { "name": "theseer/tokenizer", @@ -5211,30 +4891,35 @@ }, { "name": "webmozart/assert", - "version": "1.9.1", + "version": "1.10.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", + "php": "^7.2 || ^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" + "vimeo/psalm": "<4.6.1 || 4.6.2" }, "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" + "phpunit/phpunit": "^8.5.13" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -5258,9 +4943,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.9.1" + "source": "https://github.com/webmozarts/assert/tree/1.10.0" }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-03-09T10:59:23+00:00" } ], "aliases": [], @@ -5269,15 +4954,15 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.2||^8.0", + "php": "^7.2 || ^8.0", + "ext-simplexml": "*", "ext-ctype": "*", "ext-dom": "*", + "ext-fileinfo": "*", "ext-gd": "*", "ext-iconv": "*", - "ext-fileinfo": "*", "ext-libxml": "*", "ext-mbstring": "*", - "ext-simplexml": "*", "ext-xml": "*", "ext-xmlreader": "*", "ext-xmlwriter": "*", From e2ff14fe89746a62984f54c68044466e2c80fb12 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 28 Mar 2021 16:13:00 +0200 Subject: [PATCH 142/187] Implemented the CHISQ.DIST() Statistical function. (#1961) * Implementation of the CHISQ.DIST() statistical function for left tail distribution --- CHANGELOG.md | 2 +- .../Calculation/Calculation.php | 10 +-- .../Calculation/Statistical.php | 14 ++-- .../Statistical/Distributions/ChiSquared.php | 52 +++++++++++++-- .../Statistical/Distributions/GammaBase.php | 3 +- .../Distributions/NewtonRaphson.php | 2 +- ...ChiInvTest.php => ChiDistLeftTailTest.php} | 12 ++-- ...iDistTest.php => ChiDistRightTailTest.php} | 4 +- .../Statistical/ChiInvRightTailTest.php | 37 +++++++++++ .../Statistical/CHIDISTLeftTail.php | 64 +++++++++++++++++++ .../{CHIDIST.php => CHIDISTRightTail.php} | 0 .../{CHIINV.php => CHIINVRightTail.php} | 12 +++- 12 files changed, 183 insertions(+), 29 deletions(-) rename tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/{ChiInvTest.php => ChiDistLeftTailTest.php} (58%) rename tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/{ChiDistTest.php => ChiDistRightTailTest.php} (92%) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php create mode 100644 tests/data/Calculation/Statistical/CHIDISTLeftTail.php rename tests/data/Calculation/Statistical/{CHIDIST.php => CHIDISTRightTail.php} (100%) rename tests/data/Calculation/Statistical/{CHIINV.php => CHIINVRightTail.php} (82%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6d252d5..d7b123ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Implemented the CHITEST() Statistical function. +- Implemented the CHITEST() and CHISQ.DIST() Statistical function. - Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) ### Changed diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 62524c37..c4a88bc3 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -488,22 +488,22 @@ class Calculation ], 'CHIDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distributionRightTail'], 'argumentCount' => '2', ], 'CHISQ.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distributionLeftTail'], 'argumentCount' => '3', ], 'CHISQ.DIST.RT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distribution'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'distributionRightTail'], 'argumentCount' => '2', ], 'CHIINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverseRightTail'], 'argumentCount' => '2', ], 'CHISQ.INV' => [ @@ -513,7 +513,7 @@ class Calculation ], 'CHISQ.INV.RT' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverse'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverseRightTail'], 'argumentCount' => '2', ], 'CHITEST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 5f557431..01caba14 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -297,8 +297,8 @@ class Statistical * * @Deprecated 1.18.0 * - * @see Statistical\Distributions\ChiSquared::distribution() - * Use the distribution() method in the Statistical\Distributions\ChiSquared class instead + * @see Statistical\Distributions\ChiSquared::distributionRightTail() + * Use the distributionRightTail() method in the Statistical\Distributions\ChiSquared class instead * * @param float $value Value for the function * @param float $degrees degrees of freedom @@ -307,7 +307,7 @@ class Statistical */ public static function CHIDIST($value, $degrees) { - return Statistical\Distributions\ChiSquared::distribution($value, $degrees); + return Statistical\Distributions\ChiSquared::distributionRightTail($value, $degrees); } /** @@ -317,8 +317,8 @@ class Statistical * * @Deprecated 1.18.0 * - * @see Statistical\Distributions\ChiSquared::inverse() - * Use the inverse() method in the Statistical\Distributions\ChiSquared class instead + * @see Statistical\Distributions\ChiSquared::inverseRightTail() + * Use the inverseRightTail() method in the Statistical\Distributions\ChiSquared class instead * * @param float $probability Probability for the function * @param float $degrees degrees of freedom @@ -327,7 +327,7 @@ class Statistical */ public static function CHIINV($probability, $degrees) { - return Statistical\Distributions\ChiSquared::inverse($probability, $degrees); + return Statistical\Distributions\ChiSquared::inverseRightTail($probability, $degrees); } /** @@ -2159,7 +2159,7 @@ class Statistical /** * TINV. * - * Returns the one-tailed probability of the chi-squared distribution. + * Returns the one-tailed probability of the Student-T distribution. * * @Deprecated 1.18.0 * diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index dfd090de..409e5883 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -21,7 +21,7 @@ class ChiSquared * * @return float|string */ - public static function distribution($value, $degrees) + public static function distributionRightTail($value, $degrees) { $value = Functions::flattenSingleValue($value); $degrees = Functions::flattenSingleValue($degrees); @@ -48,16 +48,60 @@ class ChiSquared } /** - * CHIINV. + * CHIDIST. * * Returns the one-tailed probability of the chi-squared distribution. * + * @param mixed (float) $value Value for the function + * @param mixed (int) $degrees degrees of freedom + * @param mixed $cumulative + * + * @return float|string + */ + public static function distributionLeftTail($value, $degrees, $cumulative) + { + $value = Functions::flattenSingleValue($value); + $degrees = Functions::flattenSingleValue($degrees); + $cumulative = Functions::flattenSingleValue($cumulative); + + try { + $value = self::validateFloat($value); + $degrees = self::validateInt($degrees); + $cumulative = self::validateBool($cumulative); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($degrees < 1) { + return Functions::NAN(); + } + if ($value < 0) { + if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { + return 1; + } + + return Functions::NAN(); + } + + if ($cumulative === true) { + return 1 - self::distributionRightTail($value, $degrees); + } + + return (($value ** (($degrees / 2) - 1) * exp(-$value / 2))) / + ((2 ** ($degrees / 2)) * Gamma::gammaValue($degrees / 2)); + } + + /** + * CHIINV. + * + * Returns the inverse of the right-tailed probability of the chi-squared distribution. + * * @param mixed (float) $probability Probability for the function * @param mixed (int) $degrees degrees of freedom * * @return float|string */ - public static function inverse($probability, $degrees) + public static function inverseRightTail($probability, $degrees) { $probability = Functions::flattenSingleValue($probability); $degrees = Functions::flattenSingleValue($degrees); @@ -108,7 +152,7 @@ class ChiSquared $degrees = self::degrees($rows, $columns); - $result = self::distribution($result, $degrees); + $result = self::distributionRightTail($result, $degrees); return $result; } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php index 3f76787d..89170f7c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php @@ -30,14 +30,15 @@ abstract class GammaBase $xLo = 0; $xHi = $alpha * $beta * 5; - $x = $xNew = 1; $dx = 1024; + $x = $xNew = 1; $i = 0; while ((abs($dx) > Functions::PRECISION) && (++$i <= self::MAX_ITERATIONS)) { // Apply Newton-Raphson step $result = self::calculateDistribution($x, $alpha, $beta, true); $error = $result - $probability; + if ($error == 0.0) { $dx = 0; } elseif ($error < 0.0) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php index 298cdfaf..d4025f6f 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -20,8 +20,8 @@ class NewtonRaphson $xLo = 100; $xHi = 0; - $x = $xNew = 1; $dx = 1; + $x = $xNew = 1; $i = 0; while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php similarity index 58% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvTest.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php index 72680914..3c7a8d4e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class ChiInvTest extends TestCase +class ChiDistLeftTailTest extends TestCase { protected function setUp(): void { @@ -14,18 +14,18 @@ class ChiInvTest extends TestCase } /** - * @dataProvider providerCHIINV + * @dataProvider providerCHIDIST * * @param mixed $expectedResult */ - public function testCHIINV($expectedResult, ...$args): void + public function testCHIDIST($expectedResult, ...$args): void { - $result = Statistical::CHIINV(...$args); + $result = Statistical\Distributions\ChiSquared::distributionLeftTail(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCHIINV() + public function providerCHIDIST() { - return require 'tests/data/Calculation/Statistical/CHIINV.php'; + return require 'tests/data/Calculation/Statistical/CHIDISTLeftTail.php'; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php similarity index 92% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistTest.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php index 9dc7326c..26bf5ab7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class ChiDistTest extends TestCase +class ChiDistRightTailTest extends TestCase { protected function setUp(): void { @@ -26,6 +26,6 @@ class ChiDistTest extends TestCase public function providerCHIDIST() { - return require 'tests/data/Calculation/Statistical/CHIDIST.php'; + return require 'tests/data/Calculation/Statistical/CHIDISTRightTail.php'; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php new file mode 100644 index 00000000..75949f39 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php @@ -0,0 +1,37 @@ + [ + '#NUM!', + -8, 3, true, + ], + 'Degrees < 1' => [ + '#NUM!', + 8, 0, true, + ], +]; diff --git a/tests/data/Calculation/Statistical/CHIDIST.php b/tests/data/Calculation/Statistical/CHIDISTRightTail.php similarity index 100% rename from tests/data/Calculation/Statistical/CHIDIST.php rename to tests/data/Calculation/Statistical/CHIDISTRightTail.php diff --git a/tests/data/Calculation/Statistical/CHIINV.php b/tests/data/Calculation/Statistical/CHIINVRightTail.php similarity index 82% rename from tests/data/Calculation/Statistical/CHIINV.php rename to tests/data/Calculation/Statistical/CHIINVRightTail.php index f931a780..58b317e5 100644 --- a/tests/data/Calculation/Statistical/CHIINV.php +++ b/tests/data/Calculation/Statistical/CHIINVRightTail.php @@ -10,13 +10,21 @@ return [ 0.75, 10, ], [ - 18.30697345702, - 0.050001, 10, + 0.007716715545, + 0.93, 1, + ], + [ + 1.021651247532, + 0.6, 2, ], [ 0.45493642312, 0.5, 1, ], + [ + 4.351460191096, + 0.5, 5, + ], [ 0.101531044268, 0.75, 1, From e68978f1c7c33019a237ebbca43613a9671bd463 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 28 Mar 2021 19:12:45 +0200 Subject: [PATCH 143/187] Chi squared inverse left tailed (#1964) * Implementation of the CHISQ.INV() method for ChiSquared distribution left-tail --- CHANGELOG.md | 2 +- .../Calculation/Calculation.php | 2 +- .../Statistical/Distributions/ChiSquared.php | 131 ++++++++++++++++++ .../Statistical/ChiInvLeftTailTest.php | 37 +++++ .../Statistical/CHIINVLeftTail.php | 64 +++++++++ 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php create mode 100644 tests/data/Calculation/Statistical/CHIINVLeftTail.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b123ef..eb3ab111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Added -- Implemented the CHITEST() and CHISQ.DIST() Statistical function. +- Implemented the CHITEST(), CHISQ.DIST() and CHISQ.INV() and equivalent Statistical functions, for both left- and right-tailed distributions. - Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908) ### Changed diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index c4a88bc3..4dfcf9ab 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -508,7 +508,7 @@ class Calculation ], 'CHISQ.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\ChiSquared::class, 'inverseLeftTail'], 'argumentCount' => '2', ], 'CHISQ.INV.RT' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 409e5883..df3451cd 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -11,6 +11,8 @@ class ChiSquared private const MAX_ITERATIONS = 256; + private const EPS = 2.22e-16; + /** * CHIDIST. * @@ -127,6 +129,35 @@ class ChiSquared return $newtonRaphson->execute($probability); } + /** + * CHIINV. + * + * Returns the inverse of the left-tailed probability of the chi-squared distribution. + * + * @param mixed (float) $probability Probability for the function + * @param mixed (int) $degrees degrees of freedom + * + * @return float|string + */ + public static function inverseLeftTail($probability, $degrees) + { + $probability = Functions::flattenSingleValue($probability); + $degrees = Functions::flattenSingleValue($degrees); + + try { + $probability = self::validateFloat($probability); + $degrees = self::validateInt($degrees); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($probability < 0.0 || $probability > 1.0 || $degrees < 1) { + return Functions::NAN(); + } + + return self::inverseLeftTailCalculation($probability, $degrees); + } + public static function test($actual, $expected) { $rows = count($actual); @@ -167,4 +198,104 @@ class ChiSquared return ($columns - 1) * ($rows - 1); } + + private static function inverseLeftTailCalculation($probability, $degrees) + { + // bracket the root + $min = 0; + $sd = sqrt(2.0 * $degrees); + $max = 2 * $sd; + $s = -1; + + while ($s * self::pchisq($max, $degrees) > $probability * $s) { + $min = $max; + $max += 2 * $sd; + } + + // Find root using bisection + $chi2 = 0.5 * ($min + $max); + + while (($max - $min) > self::EPS * $chi2) { + if ($s * self::pchisq($chi2, $degrees) > $probability * $s) { + $min = $chi2; + } else { + $max = $chi2; + } + $chi2 = 0.5 * ($min + $max); + } + + return $chi2; + } + + private static function pchisq($chi2, $degrees) + { + return self::gammp($degrees, 0.5 * $chi2); + } + + private static function gammp($n, $x) + { + if ($x < 0.5 * $n + 1) { + return self::gser($n, $x); + } + + return 1 - self::gcf($n, $x); + } + + // Return the incomplete gamma function P(n/2,x) evaluated by + // 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) + { + $gln = Gamma::ln($n / 2); + $a = 0.5 * $n; + $ap = $a; + $sum = 1.0 / $a; + $del = $sum; + for ($i = 1; $i < 101; ++$i) { + ++$ap; + $del = $del * $x / $ap; + $sum += $del; + if ($del < $sum * self::EPS) { + break; + } + } + + return $sum * exp(-$x + $a * log($x) - $gln); + } + + // Return the incomplete gamma function Q(n/2,x) evaluated by + // 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) + { + $gln = Gamma::ln($n / 2); + $a = 0.5 * $n; + $b = $x + 1 - $a; + $fpmin = 1.e-300; + $c = 1 / $fpmin; + $d = 1 / $b; + $h = $d; + for ($i = 1; $i < 101; ++$i) { + $an = -$i * ($i - $a); + $b += 2; + $d = $an * $d + $b; + if (abs($d) < $fpmin) { + $d = $fpmin; + } + $c = $b + $an / $c; + if (abs($c) < $fpmin) { + $c = $fpmin; + } + $d = 1 / $d; + $del = $d * $c; + $h = $h * $del; + if (abs($del - 1) < self::EPS) { + break; + } + } + + return $h * exp(-$x + $a * log($x) - $gln); + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php new file mode 100644 index 00000000..962e20ad --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php @@ -0,0 +1,37 @@ + [ + '#NUM!', + -0.1, 3, + ], + 'Probability > 1' => [ + '#NUM!', + 1.1, 3, + ], + 'Freedom > 1' => [ + '#NUM!', + 0.1, 0.5, + ], +]; From b87f93f8240f0e07761d1b336926af0bf748b2b3 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 28 Mar 2021 21:42:56 +0200 Subject: [PATCH 144/187] Update remaining references in the Financial Functions code to avoid calling deprecated methods (#1965) * Update remaining references in the Financial Functions code to bypass deprecated date methods and use the new date function methods directly --- src/PhpSpreadsheet/Calculation/Financial.php | 34 ++++++++++++------- .../Financial/Securities/AccruedInterest.php | 8 ++--- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 1a67ef33..11bbf7a6 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -620,7 +620,7 @@ class Financial if (($price <= 0) || ($redemption <= 0)) { return Functions::NAN(); } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; @@ -810,7 +810,7 @@ class Financial if (($investment <= 0) || ($redemption <= 0)) { return Functions::NAN(); } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; @@ -1451,7 +1451,7 @@ class Financial if (($investment <= 0) || ($discount <= 0)) { return Functions::NAN(); } - $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis); + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); if (!is_numeric($daysBetweenSettlementAndMaturity)) { // return date error return $daysBetweenSettlementAndMaturity; @@ -1639,9 +1639,10 @@ class Financial $datesCount = count($dates); for ($i = 0; $i < $datesCount; ++$i) { - $dates[$i] = DateTime::getDateValue($dates[$i]); - if (!is_numeric($dates[$i])) { - return Functions::VALUE(); + try { + $dates[$i] = DateTimeExcel\Helpers::getDateValue($dates[$i]); + } catch (Exception $e) { + return $e->getMessage(); } } @@ -1766,7 +1767,7 @@ class Financial if ($valCount > 1 && ((min($values) > 0) || (max($values) < 0))) { return Functions::NAN(); } - $date0 = DateTime::getDateValue($dates[0]); + $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); if (is_string($date0)) { return Functions::VALUE(); } @@ -1780,7 +1781,12 @@ class Financial $values = Functions::flattenArray($values); $dates = Functions::flattenArray($dates); $valCount = count($values); - $date0 = DateTime::getDateValue($dates[0]); + + try { + $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); + } catch (Exception $e) { + return $e->getMessage(); + } $rslt = self::validateXnpv($rate, $values, $dates); if ($rslt) { return $rslt; @@ -1790,14 +1796,16 @@ class Financial if (!is_numeric($values[$i])) { return Functions::VALUE(); } - $datei = DateTime::getDateValue($dates[$i]); - if (is_string($datei)) { - return Functions::VALUE(); + + try { + $datei = DateTimeExcel\Helpers::getDateValue($dates[$i]); + } catch (Exception $e) { + return $e->getMessage(); } if ($date0 > $datei) { - $dif = $ordered ? Functions::NAN() : -DateTime::DATEDIF($datei, $date0, 'd'); + $dif = $ordered ? Functions::NAN() : -DateTimeExcel\DateDif::funcDateDif($datei, $date0, 'd'); } else { - $dif = DateTime::DATEDIF($date0, $datei, 'd'); + $dif = DateTimeExcel\DateDif::funcDateDif($date0, $datei, 'd'); } if (!is_numeric($dif)) { return $dif; diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php index f81ea13c..726b125a 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; -use PhpOffice\PhpSpreadsheet\Calculation\DateTime; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\YearFrac; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -76,12 +76,12 @@ class AccruedInterest return $e->getMessage(); } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + $daysBetweenIssueAndSettlement = YearFrac::funcYearFrac($issue, $settlement, $basis); if (!is_numeric($daysBetweenIssueAndSettlement)) { // return date error return $daysBetweenIssueAndSettlement; } - $daysBetweenFirstInterestAndSettlement = DateTime::YEARFRAC($firstinterest, $settlement, $basis); + $daysBetweenFirstInterestAndSettlement = YearFrac::funcYearFrac($firstinterest, $settlement, $basis); if (!is_numeric($daysBetweenFirstInterestAndSettlement)) { // return date error return $daysBetweenFirstInterestAndSettlement; @@ -132,7 +132,7 @@ class AccruedInterest return $e->getMessage(); } - $daysBetweenIssueAndSettlement = DateTime::YEARFRAC($issue, $settlement, $basis); + $daysBetweenIssueAndSettlement = YearFrac::funcYearFrac($issue, $settlement, $basis); if (!is_numeric($daysBetweenIssueAndSettlement)) { // return date error return $daysBetweenIssueAndSettlement; From 1c92b7611ab1bb3b6e43c6380830361c7e723d16 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 29 Mar 2021 12:59:46 +0200 Subject: [PATCH 145/187] Extract Percentile-type functions from Statistics (#1966) * Extract Percentile-type functions from Statistics (e.g. PERCENTILE(), PERCENTRANK(), QUARTILE(), and RANK()) * Unit test for PERCENTILE() with an empty (of numbers) dataset --- .../Calculation/Calculation.php | 14 +- .../Calculation/Statistical.php | 132 +++-------- .../Statistical/BaseValidations.php | 27 +++ .../Calculation/Statistical/Confidence.php | 25 ++- .../Calculation/Statistical/Percentiles.php | 207 ++++++++++++++++++ .../Calculation/Statistical/Permutations.php | 40 ++-- .../Calculation/Statistical/Trends.php | 6 +- .../Calculation/Statistical/PERCENTILE.php | 24 ++ .../Calculation/Statistical/PERCENTRANK.php | 7 +- .../Calculation/Statistical/PERMUTATIONA.php | 8 + .../data/Calculation/Statistical/QUARTILE.php | 4 + tests/data/Calculation/Statistical/RANK.php | 41 ++-- 12 files changed, 378 insertions(+), 157 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 4dfcf9ab..4f95c5b4 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1903,7 +1903,7 @@ class Calculation ], 'PERCENTILE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'PERCENTILE'], + 'functionCall' => [Statistical\Percentiles::class, 'PERCENTILE'], 'argumentCount' => '2', ], 'PERCENTILE.EXC' => [ @@ -1913,12 +1913,12 @@ class Calculation ], 'PERCENTILE.INC' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'PERCENTILE'], + 'functionCall' => [Statistical\Percentiles::class, 'PERCENTILE'], 'argumentCount' => '2', ], 'PERCENTRANK' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'PERCENTRANK'], + 'functionCall' => [Statistical\Percentiles::class, 'PERCENTRANK'], 'argumentCount' => '2,3', ], 'PERCENTRANK.EXC' => [ @@ -1928,7 +1928,7 @@ class Calculation ], 'PERCENTRANK.INC' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'PERCENTRANK'], + 'functionCall' => [Statistical\Percentiles::class, 'PERCENTRANK'], 'argumentCount' => '2,3', ], 'PERMUT' => [ @@ -2018,7 +2018,7 @@ class Calculation ], 'QUARTILE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'QUARTILE'], + 'functionCall' => [Statistical\Percentiles::class, 'QUARTILE'], 'argumentCount' => '2', ], 'QUARTILE.EXC' => [ @@ -2028,7 +2028,7 @@ class Calculation ], 'QUARTILE.INC' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'QUARTILE'], + 'functionCall' => [Statistical\Percentiles::class, 'QUARTILE'], 'argumentCount' => '2', ], 'QUOTIENT' => [ @@ -2058,7 +2058,7 @@ class Calculation ], 'RANK' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'RANK'], + 'functionCall' => [Statistical\Percentiles::class, 'RANK'], 'argumentCount' => '2,3', ], 'RANK.AVG' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 01caba14..ce80fa79 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -1665,45 +1665,18 @@ class Statistical * Excel Function: * PERCENTILE(value1[,value2[, ...]],entry) * + * @Deprecated 1.18.0 + * + * @see Statistical\Percentiles::PERCENTILE() + * Use the PERCENTILE() method in the Statistical\Percentiles class instead + * * @param mixed $args Data values * * @return float|string The result, or a string containing an error */ public static function PERCENTILE(...$args) { - $aArgs = Functions::flattenArray($args); - - // Calculate - $entry = array_pop($aArgs); - - if ((is_numeric($entry)) && (!is_string($entry))) { - if (($entry < 0) || ($entry > 1)) { - return Functions::NAN(); - } - $mArgs = []; - foreach ($aArgs as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $mArgs[] = $arg; - } - } - $mValueCount = count($mArgs); - if ($mValueCount > 0) { - sort($mArgs); - $count = Counts::COUNT($mArgs); - $index = $entry * ($count - 1); - $iBase = floor($index); - if ($index == $iBase) { - return $mArgs[$index]; - } - $iNext = $iBase + 1; - $iProportion = $index - $iBase; - - return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion); - } - } - - return Functions::VALUE(); + return Statistical\Percentiles::PERCENTILE(...$args); } /** @@ -1714,6 +1687,11 @@ class Statistical * rather than floored (as MS Excel), so value 3 for a value set of 1, 2, 3, 4 will return * 0.667 rather than 0.666 * + * @Deprecated 1.18.0 + * + * @see Statistical\Percentiles::PERCENTRANK() + * Use the PERCENTRANK() method in the Statistical\Percentiles class instead + * * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers * @param mixed (int) $value the number whose rank you want to find * @param mixed (int) $significance the number of significant digits for the returned percentage value @@ -1722,38 +1700,7 @@ class Statistical */ public static function PERCENTRANK($valueSet, $value, $significance = 3) { - $valueSet = Functions::flattenArray($valueSet); - $value = Functions::flattenSingleValue($value); - $significance = ($significance === null) ? 3 : (int) Functions::flattenSingleValue($significance); - - foreach ($valueSet as $key => $valueEntry) { - if (!is_numeric($valueEntry)) { - unset($valueSet[$key]); - } - } - sort($valueSet, SORT_NUMERIC); - $valueCount = count($valueSet); - if ($valueCount == 0) { - return Functions::NAN(); - } - - $valueAdjustor = $valueCount - 1; - if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) { - return Functions::NA(); - } - - $pos = array_search($value, $valueSet); - if ($pos === false) { - $pos = 0; - $testValue = $valueSet[0]; - while ($testValue < $value) { - $testValue = $valueSet[++$pos]; - } - --$pos; - $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos])); - } - - return round($pos / $valueAdjustor, $significance); + return Statistical\Percentiles::PERCENTRANK($valueSet, $value, $significance); } /** @@ -1811,27 +1758,18 @@ class Statistical * Excel Function: * QUARTILE(value1[,value2[, ...]],entry) * + * @Deprecated 1.18.0 + * + * @see Statistical\Percentiles::QUARTILE() + * Use the QUARTILE() method in the Statistical\Percentiles class instead + * * @param mixed $args Data values * * @return float|string The result, or a string containing an error */ public static function QUARTILE(...$args) { - $aArgs = Functions::flattenArray($args); - $entry = array_pop($aArgs); - - // Calculate - if ((is_numeric($entry)) && (!is_string($entry))) { - $entry = floor($entry); - $entry /= 4; - if (($entry < 0) || ($entry > 1)) { - return Functions::NAN(); - } - - return self::PERCENTILE($aArgs, $entry); - } - - return Functions::VALUE(); + return Statistical\Percentiles::QUARTILE(...$args); } /** @@ -1839,36 +1777,20 @@ class Statistical * * Returns the rank of a number in a list of numbers. * - * @param int $value the number whose rank you want to find - * @param float[] $valueSet An array of, or a reference to, a list of numbers - * @param int $order Order to sort the values in the value set + * @Deprecated 1.18.0 + * + * @see Statistical\Percentiles::RANK() + * Use the RANK() method in the Statistical\Percentiles class instead + * + * @param mixed (float) $value the number whose rank you want to find + * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers + * @param mixed (int) $order Order to sort the values in the value set * * @return float|string The result, or a string containing an error */ public static function RANK($value, $valueSet, $order = 0) { - $value = Functions::flattenSingleValue($value); - $valueSet = Functions::flattenArray($valueSet); - $order = ($order === null) ? 0 : (int) Functions::flattenSingleValue($order); - - foreach ($valueSet as $key => $valueEntry) { - if (!is_numeric($valueEntry)) { - unset($valueSet[$key]); - } - } - - if ($order == 0) { - sort($valueSet, SORT_NUMERIC); - } else { - rsort($valueSet, SORT_NUMERIC); - } - - $pos = array_search($value, $valueSet); - if ($pos === false) { - return Functions::NA(); - } - - return ++$pos; + return Statistical\Percentiles::RANK($value, $valueSet, $order); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php new file mode 100644 index 00000000..1dbe4212 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php @@ -0,0 +1,27 @@ += 1)) { - return Functions::NAN(); - } - if (($stdDev <= 0) || ($size < 1)) { - return Functions::NAN(); - } - - return Statistical::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); + try { + $alpha = self::validateFloat($alpha); + $stdDev = self::validateFloat($stdDev); + $size = self::validateInt($size); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if (($alpha <= 0) || ($alpha >= 1) || ($stdDev <= 0) || ($size < 1)) { + return Functions::NAN(); + } + + return Statistical::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php b/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php new file mode 100644 index 00000000..0001b7bf --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php @@ -0,0 +1,207 @@ +getMessage(); + } + + if (($entry < 0) || ($entry > 1)) { + return Functions::NAN(); + } + + $mArgs = self::percentileFilterValues($aArgs); + $mValueCount = count($mArgs); + if ($mValueCount > 0) { + sort($mArgs); + $count = Counts::COUNT($mArgs); + $index = $entry * ($count - 1); + $iBase = floor($index); + if ($index == $iBase) { + return $mArgs[$index]; + } + $iNext = $iBase + 1; + $iProportion = $index - $iBase; + + return $mArgs[$iBase] + (($mArgs[$iNext] - $mArgs[$iBase]) * $iProportion); + } + + return Functions::NAN(); + } + + /** + * PERCENTRANK. + * + * Returns the rank of a value in a data set as a percentage of the data set. + * Note that the returned rank is simply rounded to the appropriate significant digits, + * rather than floored (as MS Excel), so value 3 for a value set of 1, 2, 3, 4 will return + * 0.667 rather than 0.666 + * + * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers + * @param mixed (int) $value the number whose rank you want to find + * @param mixed (int) $significance the number of significant digits for the returned percentage value + * + * @return float|string (string if result is an error) + */ + public static function PERCENTRANK($valueSet, $value, $significance = 3) + { + $valueSet = Functions::flattenArray($valueSet); + $value = Functions::flattenSingleValue($value); + $significance = ($significance === null) ? 3 : Functions::flattenSingleValue($significance); + + try { + $value = self::validateFloat($value); + $significance = self::validateInt($significance); + } catch (Exception $e) { + return $e->getMessage(); + } + + $valueSet = self::rankFilterValues($valueSet); + $valueCount = count($valueSet); + if ($valueCount == 0) { + return Functions::NA(); + } + sort($valueSet, SORT_NUMERIC); + + $valueAdjustor = $valueCount - 1; + if (($value < $valueSet[0]) || ($value > $valueSet[$valueAdjustor])) { + return Functions::NA(); + } + + $pos = array_search($value, $valueSet); + if ($pos === false) { + $pos = 0; + $testValue = $valueSet[0]; + while ($testValue < $value) { + $testValue = $valueSet[++$pos]; + } + --$pos; + $pos += (($value - $valueSet[$pos]) / ($testValue - $valueSet[$pos])); + } + + return round($pos / $valueAdjustor, $significance); + } + + /** + * QUARTILE. + * + * Returns the quartile of a data set. + * + * Excel Function: + * QUARTILE(value1[,value2[, ...]],entry) + * + * @param mixed $args Data values + * + * @return float|string The result, or a string containing an error + */ + public static function QUARTILE(...$args) + { + $aArgs = Functions::flattenArray($args); + $entry = array_pop($aArgs); + + try { + $entry = self::validateFloat($entry); + } catch (Exception $e) { + return $e->getMessage(); + } + + $entry = floor($entry); + $entry /= 4; + if (($entry < 0) || ($entry > 1)) { + return Functions::NAN(); + } + + return self::PERCENTILE($aArgs, $entry); + } + + /** + * RANK. + * + * Returns the rank of a number in a list of numbers. + * + * @param mixed (float) $value the number whose rank you want to find + * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers + * @param mixed (int) $order Order to sort the values in the value set + * + * @return float|string The result, or a string containing an error + */ + public static function RANK($value, $valueSet, $order = self::RANK_SORT_DESCENDING) + { + $value = Functions::flattenSingleValue($value); + $valueSet = Functions::flattenArray($valueSet); + $order = ($order === null) ? self::RANK_SORT_DESCENDING : Functions::flattenSingleValue($order); + + try { + $value = self::validateFloat($value); + $order = self::validateInt($order); + } catch (Exception $e) { + return $e->getMessage(); + } + + $valueSet = self::rankFilterValues($valueSet); + if ($order === self::RANK_SORT_DESCENDING) { + rsort($valueSet, SORT_NUMERIC); + } else { + sort($valueSet, SORT_NUMERIC); + } + + $pos = array_search($value, $valueSet); + if ($pos === false) { + return Functions::NA(); + } + + return ++$pos; + } + + protected static function percentileFilterValues(array $dataSet) + { + return array_filter( + $dataSet, + function ($value): bool { + return is_numeric($value) && !is_string($value); + } + ); + } + + protected static function rankFilterValues(array $dataSet) + { + return array_filter( + $dataSet, + function ($value): bool { + return is_numeric($value); + } + ); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php index 343a056c..84cdfea1 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -2,11 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Permutations { + use BaseValidations; + /** * PERMUT. * @@ -26,16 +29,18 @@ class Permutations $numObjs = Functions::flattenSingleValue($numObjs); $numInSet = Functions::flattenSingleValue($numInSet); - if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { - $numInSet = floor($numInSet); - if ($numObjs < $numInSet) { - return Functions::NAN(); - } - - return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)); + try { + $numObjs = self::validateInt($numObjs); + $numInSet = self::validateInt($numInSet); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if ($numObjs < $numInSet) { + return Functions::NAN(); + } + + return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)); } /** @@ -54,16 +59,17 @@ class Permutations $numObjs = Functions::flattenSingleValue($numObjs); $numInSet = Functions::flattenSingleValue($numInSet); - if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { - $numObjs = floor($numObjs); - $numInSet = floor($numInSet); - if ($numObjs < 0 || $numInSet < 0) { - return Functions::NAN(); - } - - return $numObjs ** $numInSet; + try { + $numObjs = self::validateInt($numObjs); + $numInSet = self::validateInt($numInSet); + } catch (Exception $e) { + return $e->getMessage(); } - return Functions::VALUE(); + if ($numObjs < 0 || $numInSet < 0) { + return Functions::NAN(); + } + + return $numObjs ** $numInSet; } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index b1dfbaef..8c88c54c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -8,6 +8,8 @@ use PhpOffice\PhpSpreadsheet\Shared\Trend\Trend; class Trends { + use BaseValidations; + private static function filterTrendValues(array &$array1, array &$array2): void { foreach ($array1 as $key => $value) { @@ -116,11 +118,9 @@ class Trends public static function FORECAST($xValue, $yValues, $xValues) { $xValue = Functions::flattenSingleValue($xValue); - if (!is_numeric($xValue)) { - return Functions::VALUE(); - } try { + $xValue = self::validateFloat($xValue); self::checkTrendArrays($yValues, $xValues); self::validateTrendArrays($yValues, $xValues); } catch (Exception $e) { diff --git a/tests/data/Calculation/Statistical/PERCENTILE.php b/tests/data/Calculation/Statistical/PERCENTILE.php index 121e49c0..cf08ce88 100644 --- a/tests/data/Calculation/Statistical/PERCENTILE.php +++ b/tests/data/Calculation/Statistical/PERCENTILE.php @@ -25,10 +25,34 @@ return [ 48.4, [10.5, 7.2, 200, 5.4, 8.1, 0.8], ], + [ + 2, + [2, 1, 6, 4, 3, 5, 0.2], + ], + [ + 4, + [2, 1, 6, 4, 3, 5, 0.6], + ], + [ + 3.5, + [2, 1, 6, 4, 3, 5, 0.5], + ], + [ + 5.75, + [2, 1, 6, 4, 3, 5, 0.95], + ], [ '#NUM!', [1, 2, 3, 4, -0.3], ], + [ + '#NUM!', + [1, 2, 3, 4, 1.5], + ], + [ + '#NUM!', + ['A', 'B', 0.5], + ], [ '#VALUE!', [1, 2, 3, 4, 'NaN'], diff --git a/tests/data/Calculation/Statistical/PERCENTRANK.php b/tests/data/Calculation/Statistical/PERCENTRANK.php index 3ab019ac..3787a7ac 100644 --- a/tests/data/Calculation/Statistical/PERCENTRANK.php +++ b/tests/data/Calculation/Statistical/PERCENTRANK.php @@ -56,10 +56,15 @@ return [ 2, ], [ - '#NUM!', + '#VALUE!', ['A', 'B', 'C', 'D'], 'E', ], + [ + '#N/A', + ['A', 'B', 'C', 'D'], + 3, + ], [ '#N/A', [1, 2, 3, 4], diff --git a/tests/data/Calculation/Statistical/PERMUTATIONA.php b/tests/data/Calculation/Statistical/PERMUTATIONA.php index 6bc118b3..701f5eac 100644 --- a/tests/data/Calculation/Statistical/PERMUTATIONA.php +++ b/tests/data/Calculation/Statistical/PERMUTATIONA.php @@ -21,6 +21,14 @@ return [ '#NUM!', -1, 2, ], + [ + '#NUM!', + 1, -2, + ], + [ + '#VALUE!', + 'NaN', 31, + ], [ '#VALUE!', 49, 'NaN', diff --git a/tests/data/Calculation/Statistical/QUARTILE.php b/tests/data/Calculation/Statistical/QUARTILE.php index 80b2bf09..26a7902f 100644 --- a/tests/data/Calculation/Statistical/QUARTILE.php +++ b/tests/data/Calculation/Statistical/QUARTILE.php @@ -37,6 +37,10 @@ return [ 9.25, [7, 8, 9, 10, 3], ], + [ + '#NUM!', + [7, 8, 9, 10, -1], + ], [ '#NUM!', [7, 8, 9, 10, 5], diff --git a/tests/data/Calculation/Statistical/RANK.php b/tests/data/Calculation/Statistical/RANK.php index 0640bb43..6cb60e24 100644 --- a/tests/data/Calculation/Statistical/RANK.php +++ b/tests/data/Calculation/Statistical/RANK.php @@ -1,38 +1,53 @@ Date: Tue, 30 Mar 2021 10:11:19 +0900 Subject: [PATCH 146/187] Document release process --- CONTRIBUTING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index aed13fe2..f5953533 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,3 +9,12 @@ If you would like to contribute, here are some notes and guidelines: - All code changes must be validated by `composer check` - [Helpful article about forking](https://help.github.com/articles/fork-a-repo/ "Forking a GitHub repository") - [Helpful article about pull requests](https://help.github.com/articles/using-pull-requests/ "Pull Requests") + +## How to release + +1. Complete CHANGELOG.md and commit +2. Create an annotated tag + 1. `git tag -a 1.2.3` + 2. Tag subject must be the version number, eg: `1.2.3` + 3. Tag body must be a copy-paste of the changelog entries +3. Push tag with `git push --tags`, GitHub Actions will create a GitHub release automatically From 029f345987b4f1086fe4134d6dd5303f0e50e691 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 30 Mar 2021 22:49:10 +0200 Subject: [PATCH 147/187] Extract Binomial Distribution functions from Statistical (#1974) * Extract Binomial Distribution functions from Statistical Replace the old MS algorithm for CRITBINOM() (which has now been replaced with te BINOM.INV() function) with a brute force approach - I'll look to refine it later. The MS algorithm is no longer documented, and the implementation produced erroneous results anyway * Exract the NEGBINOMDIST() function as well; still need to add a cumulative flag to support the additional argument for the newer NEGBINOM.DIST() function * Rationalise validation of probability arguments --- .../Calculation/Calculation.php | 12 +- .../Calculation/Financial/CashFlow/Single.php | 7 + .../Calculation/Statistical.php | 170 ++------------- .../Distributions/BaseValidations.php | 11 + .../Statistical/Distributions/Beta.php | 4 +- .../Statistical/Distributions/Binomial.php | 200 ++++++++++++++++++ .../Statistical/Distributions/ChiSquared.php | 8 +- .../Statistical/Distributions/Gamma.php | 4 +- .../Distributions/NewtonRaphson.php | 2 +- .../Statistical/Distributions/StudentT.php | 4 +- .../Statistical/BinomDistRangeTest.php | 31 +++ .../Functions/Statistical/BinomInvTest.php | 31 +++ .../Calculation/Statistical/BINOMDIST.php | 22 +- .../Statistical/BINOMDISTRANGE.php | 72 +++++++ .../data/Calculation/Statistical/BINOMINV.php | 60 ++++++ .../Calculation/Statistical/CRITBINOM.php | 24 --- .../Calculation/Statistical/NEGBINOMDIST.php | 16 ++ 17 files changed, 484 insertions(+), 194 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php create mode 100644 tests/data/Calculation/Statistical/BINOMDISTRANGE.php create mode 100644 tests/data/Calculation/Statistical/BINOMINV.php delete mode 100644 tests/data/Calculation/Statistical/CRITBINOM.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 4f95c5b4..2026ce62 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -418,22 +418,22 @@ class Calculation ], 'BINOMDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'BINOMDIST'], + 'functionCall' => [Statistical\Distributions\Binomial::class, 'distribution'], 'argumentCount' => '4', ], 'BINOM.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'BINOMDIST'], + 'functionCall' => [Statistical\Distributions\Binomial::class, 'distribution'], 'argumentCount' => '4', ], 'BINOM.DIST.RANGE' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\Binomial::class, 'range'], 'argumentCount' => '3,4', ], 'BINOM.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [Statistical\Distributions\Binomial::class, 'inverse'], 'argumentCount' => '3', ], 'BITAND' => [ @@ -695,7 +695,7 @@ class Calculation ], 'CRITBINOM' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'CRITBINOM'], + 'functionCall' => [Statistical\Distributions\Binomial::class, 'inverse'], 'argumentCount' => '3', ], 'CSC' => [ @@ -1751,7 +1751,7 @@ class Calculation ], 'NEGBINOMDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NEGBINOMDIST'], + 'functionCall' => [Statistical\Distributions\Binomial::class, 'negative'], 'argumentCount' => '3', ], 'NEGBINOM.DIST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php new file mode 100644 index 00000000..3f1c8bc6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php @@ -0,0 +1,7 @@ + $trials)) { - return Functions::NAN(); - } - if (($probability < 0) || ($probability > 1)) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - $summer = 0; - for ($i = 0; $i <= $value; ++$i) { - $summer += MathTrig::COMBIN($trials, $i) * $probability ** $i * (1 - $probability) ** ($trials - $i); - } - - return $summer; - } - - return MathTrig::COMBIN($trials, $value) * $probability ** $value * (1 - $probability) ** ($trials - $value); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Binomial::distribution($value, $trials, $probability, $cumulative); } /** @@ -510,6 +488,11 @@ class Statistical * * See https://support.microsoft.com/en-us/help/828117/ for details of the algorithm used * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Binomial::inverse() + * Use the inverse() method in the Statistical\Distributions\Binomial class instead + * * @param float $trials number of Bernoulli trials * @param float $probability probability of a success on each trial * @param float $alpha criterion value @@ -523,110 +506,7 @@ class Statistical */ public static function CRITBINOM($trials, $probability, $alpha) { - $trials = floor(Functions::flattenSingleValue($trials)); - $probability = Functions::flattenSingleValue($probability); - $alpha = Functions::flattenSingleValue($alpha); - - if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) { - $trials = (int) $trials; - if ($trials < 0) { - return Functions::NAN(); - } elseif (($probability < 0.0) || ($probability > 1.0)) { - return Functions::NAN(); - } elseif (($alpha < 0.0) || ($alpha > 1.0)) { - return Functions::NAN(); - } - - if ($alpha <= 0.5) { - $t = sqrt(log(1 / ($alpha * $alpha))); - $trialsApprox = 0 - ($t + (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t)); - } else { - $t = sqrt(log(1 / (1 - $alpha) ** 2)); - $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t); - } - - $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability))); - if ($Guess < 0) { - $Guess = 0; - } elseif ($Guess > $trials) { - $Guess = $trials; - } - - $TotalUnscaledProbability = $UnscaledPGuess = $UnscaledCumPGuess = 0.0; - $EssentiallyZero = 10e-12; - - $m = floor($trials * $probability); - ++$TotalUnscaledProbability; - if ($m == $Guess) { - ++$UnscaledPGuess; - } - if ($m <= $Guess) { - ++$UnscaledCumPGuess; - } - - $PreviousValue = 1; - $Done = false; - $k = $m + 1; - while ((!$Done) && ($k <= $trials)) { - $CurrentValue = $PreviousValue * ($trials - $k + 1) * $probability / ($k * (1 - $probability)); - $TotalUnscaledProbability += $CurrentValue; - if ($k == $Guess) { - $UnscaledPGuess += $CurrentValue; - } - if ($k <= $Guess) { - $UnscaledCumPGuess += $CurrentValue; - } - if ($CurrentValue <= $EssentiallyZero) { - $Done = true; - } - $PreviousValue = $CurrentValue; - ++$k; - } - - $PreviousValue = 1; - $Done = false; - $k = $m - 1; - while ((!$Done) && ($k >= 0)) { - $CurrentValue = $PreviousValue * $k + 1 * (1 - $probability) / (($trials - $k) * $probability); - $TotalUnscaledProbability += $CurrentValue; - if ($k == $Guess) { - $UnscaledPGuess += $CurrentValue; - } - if ($k <= $Guess) { - $UnscaledCumPGuess += $CurrentValue; - } - if ($CurrentValue <= $EssentiallyZero) { - $Done = true; - } - $PreviousValue = $CurrentValue; - --$k; - } - - $PGuess = $UnscaledPGuess / $TotalUnscaledProbability; - $CumPGuess = $UnscaledCumPGuess / $TotalUnscaledProbability; - - $CumPGuessMinus1 = $CumPGuess - 1; - - while (true) { - if (($CumPGuessMinus1 < $alpha) && ($CumPGuess >= $alpha)) { - return $Guess; - } elseif (($CumPGuessMinus1 < $alpha) && ($CumPGuess < $alpha)) { - $PGuessPlus1 = $PGuess * ($trials - $Guess) * $probability / $Guess / (1 - $probability); - $CumPGuessMinus1 = $CumPGuess; - $CumPGuess = $CumPGuess + $PGuessPlus1; - $PGuess = $PGuessPlus1; - ++$Guess; - } elseif (($CumPGuessMinus1 >= $alpha) && ($CumPGuess >= $alpha)) { - $PGuessMinus1 = $PGuess * $Guess * (1 - $probability) / ($trials - $Guess + 1) / $probability; - $CumPGuess = $CumPGuessMinus1; - $CumPGuessMinus1 = $CumPGuessMinus1 - $PGuess; - $PGuess = $PGuessMinus1; - --$Guess; - } - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Binomial::inverse($trials, $probability, $alpha); } /** @@ -1502,6 +1382,11 @@ class Statistical * distribution, except that the number of successes is fixed, and the number of trials is * variable. Like the binomial, trials are assumed to be independent. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Binomial::negative::mode() + * Use the negative() method in the Statistical\Distributions\Binomial class instead + * * @param mixed (float) $failures Number of Failures * @param mixed (float) $successes Threshold number of Successes * @param mixed (float) $probability Probability of success on each trial @@ -1510,26 +1395,7 @@ class Statistical */ public static function NEGBINOMDIST($failures, $successes, $probability) { - $failures = floor(Functions::flattenSingleValue($failures)); - $successes = floor(Functions::flattenSingleValue($successes)); - $probability = Functions::flattenSingleValue($probability); - - if ((is_numeric($failures)) && (is_numeric($successes)) && (is_numeric($probability))) { - if (($failures < 0) || ($successes < 1)) { - return Functions::NAN(); - } elseif (($probability < 0) || ($probability > 1)) { - return Functions::NAN(); - } - if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { - if (($failures + $successes - 1) <= 0) { - return Functions::NAN(); - } - } - - return (MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * ($probability ** $successes) * ((1 - $probability) ** $failures); - } - - return Functions::VALUE(); + return Statistical\Distributions\Binomial::negative($failures, $successes, $probability); } /** diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php index a8ab3e89..a2e0b042 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php @@ -33,4 +33,15 @@ trait BaseValidations return (bool) $value; } + + protected static function validateProbability($probability) + { + $probability = self::validateFloat($probability); + + if ($probability < 0.0 || $probability > 1.0) { + throw new Exception(Functions::NAN()); + } + + return $probability; + } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php index c18973ce..30b8d02a 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php @@ -83,7 +83,7 @@ class Beta $rMax = Functions::flattenSingleValue($rMax); try { - $probability = self::validateFloat($probability); + $probability = self::validateProbability($probability); $alpha = self::validateFloat($alpha); $beta = self::validateFloat($beta); $rMax = self::validateFloat($rMax); @@ -97,7 +97,7 @@ class Beta $rMin = $rMax; $rMax = $tmp; } - if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0) || ($probability > 1)) { + if (($alpha <= 0) || ($beta <= 0) || ($rMin == $rMax) || ($probability <= 0.0)) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php new file mode 100644 index 00000000..2ab1fe67 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php @@ -0,0 +1,200 @@ +getMessage(); + } + + if (($value < 0) || ($value > $trials)) { + return Functions::NAN(); + } + + if ($cumulative) { + return self::calculateCumulativeBinomial($value, $trials, $probability); + } + + return MathTrig::COMBIN($trials, $value) * $probability ** $value * (1 - $probability) ** ($trials - $value); + } + + /** + * BINOM.DIST.RANGE. + * + * Returns returns the Binomial Distribution probability for the number of successes from a specified number + * of trials falling into a specified range. + * + * @param mixed (int) $trials Number of trials + * @param mixed (float) $probability Probability of success on each trial + * @param mixed (int) $successes The number of successes in trials + * @param mixed (int) $limit Upper limit for successes in trials + * + * @return float|string + */ + public static function range($trials, $probability, $successes, $limit = null) + { + $trials = Functions::flattenSingleValue($trials); + $probability = Functions::flattenSingleValue($probability); + $successes = Functions::flattenSingleValue($successes); + $limit = ($limit === null) ? $successes : Functions::flattenSingleValue($limit); + + try { + $trials = self::validateInt($trials); + $probability = self::validateProbability($probability); + $successes = self::validateInt($successes); + $limit = self::validateInt($limit); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (($successes < 0) || ($successes > $trials)) { + return Functions::NAN(); + } + if (($limit < 0) || ($limit > $trials) || $limit < $successes) { + return Functions::NAN(); + } + + $summer = 0; + for ($i = $successes; $i <= $limit; ++$i) { + $summer += MathTrig::COMBIN($trials, $i) * $probability ** $i * (1 - $probability) ** ($trials - $i); + } + + return $summer; + } + + /** + * NEGBINOMDIST. + * + * Returns the negative binomial distribution. NEGBINOMDIST returns the probability that + * there will be number_f failures before the number_s-th success, when the constant + * probability of a success is probability_s. This function is similar to the binomial + * distribution, except that the number of successes is fixed, and the number of trials is + * variable. Like the binomial, trials are assumed to be independent. + * + * @param mixed (float) $failures Number of Failures + * @param mixed (float) $successes Threshold number of Successes + * @param mixed (float) $probability Probability of success on each trial + * + * @return float|string The result, or a string containing an error + * + * TODO Add support for the cumulative flag not present for NEGBINOMDIST, but introduced for NEGBINOM.DIST + * The cumulative default should be false to reflect the behaviour of NEGBINOMDIST + */ + public static function negative($failures, $successes, $probability) + { + $failures = Functions::flattenSingleValue($failures); + $successes = Functions::flattenSingleValue($successes); + $probability = Functions::flattenSingleValue($probability); + + try { + $failures = self::validateInt($failures); + $successes = self::validateInt($successes); + $probability = self::validateProbability($probability); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (($failures < 0) || ($successes < 1)) { + return Functions::NAN(); + } + if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) { + if (($failures + $successes - 1) <= 0) { + return Functions::NAN(); + } + } + + return (MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * + ($probability ** $successes) * ((1 - $probability) ** $failures); + } + + /** + * CRITBINOM. + * + * Returns the smallest value for which the cumulative binomial distribution is greater + * than or equal to a criterion value + * + * @param float $trials number of Bernoulli trials + * @param float $probability probability of a success on each trial + * @param float $alpha criterion value + * + * @return int|string + */ + public static function inverse($trials, $probability, $alpha) + { + $trials = Functions::flattenSingleValue($trials); + $probability = Functions::flattenSingleValue($probability); + $alpha = Functions::flattenSingleValue($alpha); + + try { + $trials = self::validateInt($trials); + $probability = self::validateProbability($probability); + $alpha = self::validateFloat($alpha); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($trials < 0) { + return Functions::NAN(); + } elseif (($alpha < 0.0) || ($alpha > 1.0)) { + return Functions::NAN(); + } + + $successes = 0; + while (true && $successes <= $trials) { + $result = self::calculateCumulativeBinomial($successes, $trials, $probability); + if ($result >= $alpha) { + break; + } + ++$successes; + } + + return $successes; + } + + /** + * @return float|int + */ + private static function calculateCumulativeBinomial(int $value, int $trials, float $probability) + { + $summer = 0; + for ($i = 0; $i <= $value; ++$i) { + $summer += MathTrig::COMBIN($trials, $i) * $probability ** $i * (1 - $probability) ** ($trials - $i); + } + + return $summer; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index df3451cd..3ebe1dc5 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -109,13 +109,13 @@ class ChiSquared $degrees = Functions::flattenSingleValue($degrees); try { - $probability = self::validateFloat($probability); + $probability = self::validateProbability($probability); $degrees = self::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } - if ($probability < 0.0 || $probability > 1.0 || $degrees < 1) { + if ($degrees < 1) { return Functions::NAN(); } @@ -145,13 +145,13 @@ class ChiSquared $degrees = Functions::flattenSingleValue($degrees); try { - $probability = self::validateFloat($probability); + $probability = self::validateProbability($probability); $degrees = self::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } - if ($probability < 0.0 || $probability > 1.0 || $degrees < 1) { + if ($degrees < 1) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php index aa487329..2ea28391 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php @@ -87,14 +87,14 @@ class Gamma extends GammaBase $beta = Functions::flattenSingleValue($beta); try { - $probability = self::validateFloat($probability); + $probability = self::validateProbability($probability); $alpha = self::validateFloat($alpha); $beta = self::validateFloat($beta); } catch (Exception $e) { return $e->getMessage(); } - if (($alpha <= 0.0) || ($beta <= 0.0) || ($probability < 0.0) || ($probability > 1.0)) { + if (($alpha <= 0.0) || ($beta <= 0.0)) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php index d4025f6f..26211672 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php @@ -15,7 +15,7 @@ class NewtonRaphson $this->callback = $callback; } - public function execute($probability) + public function execute(float $probability) { $xLo = 100; $xHi = 0; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php index a6d23c6b..ed02fe4d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php @@ -59,13 +59,13 @@ class StudentT $degrees = Functions::flattenSingleValue($degrees); try { - $probability = self::validateFloat($probability); + $probability = self::validateProbability($probability); $degrees = self::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } - if ($probability < 0.0 || $probability > 1.0 || $degrees <= 0) { + if ($degrees <= 0) { return Functions::NAN(); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php new file mode 100644 index 00000000..8db391e1 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php @@ -0,0 +1,31 @@ + Date: Wed, 31 Mar 2021 21:45:06 +0200 Subject: [PATCH 148/187] Extract a few more Distribution functions from Statistical (#1975) * Extract a few more Distribution functions from Statistical; this time EXPONDIST() and HYPGEOMDIST() * Extract the F Distribution (although only F.DIST() is implemented so far * Updae docblocks * PHPCS --- .../Calculation/Calculation.php | 8 +- .../Calculation/Statistical.php | 129 ++++++------------ .../Statistical/Distributions/Exponential.php | 49 +++++++ .../Statistical/Distributions/F.php | 59 ++++++++ .../Distributions/HyperGeometric.php | 56 ++++++++ .../{FDist2Test.php => FDistTest.php} | 10 +- .../Calculation/Statistical/EXPONDIST.php | 20 +++ tests/data/Calculation/Statistical/FDIST.php | 80 +++++++++++ tests/data/Calculation/Statistical/FDIST2.php | 17 --- .../Calculation/Statistical/HYPGEOMDIST.php | 34 ++++- 10 files changed, 344 insertions(+), 118 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php rename tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/{FDist2Test.php => FDistTest.php} (70%) create mode 100644 tests/data/Calculation/Statistical/FDIST.php delete mode 100644 tests/data/Calculation/Statistical/FDIST2.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 2026ce62..ef1be8c2 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -980,12 +980,12 @@ class Calculation ], 'EXPONDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'EXPONDIST'], + 'functionCall' => [Statistical\Distributions\Exponential::class, 'distribution'], 'argumentCount' => '3', ], 'EXPON.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'EXPONDIST'], + 'functionCall' => [Statistical\Distributions\Exponential::class, 'distribution'], 'argumentCount' => '3', ], 'FACT' => [ @@ -1010,7 +1010,7 @@ class Calculation ], 'F.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'FDIST2'], + 'functionCall' => [Statistical\Distributions\F::class, 'distribution'], 'argumentCount' => '4', ], 'F.DIST.RT' => [ @@ -1248,7 +1248,7 @@ class Calculation ], 'HYPGEOMDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'HYPGEOMDIST'], + 'functionCall' => [Statistical\Distributions\HyperGeometric::class, 'distribution'], 'argumentCount' => '4', ], 'HYPGEOM.DIST' => [ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index bfa00918..1576af98 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -116,12 +116,12 @@ class Statistical * * @Deprecated 1.17.0 * + * @see Statistical\Averages::averageDeviations() + * Use the averageDeviations() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string - * - *@see Statistical\Averages::averageDeviations() - * Use the averageDeviations() method in the Statistical\Averages class instead */ public static function AVEDEV(...$args) { @@ -160,12 +160,12 @@ class Statistical * * @Deprecated 1.17.0 * + * @see Statistical\Averages::averageA() + * Use the averageA() method in the Statistical\Averages class instead + * * @param mixed ...$args Data values * * @return float|string - * - *@see Statistical\Averages::averageA() - * Use the averageA() method in the Statistical\Averages class instead */ public static function AVERAGEA(...$args) { @@ -203,7 +203,7 @@ class Statistical * * @Deprecated 1.18.0 * - *@see Statistical\Distributions\Beta::distribution() + * @see Statistical\Distributions\Beta::distribution() * Use the distribution() method in the Statistical\Distributions\Beta class instead * * @param float $value Value at which you want to evaluate the distribution @@ -498,11 +498,6 @@ class Statistical * @param float $alpha criterion value * * @return int|string - * - * @TODO Warning. This implementation differs from the algorithm detailed on the MS - * web site in that $CumPGuessMinus1 = $CumPGuess - 1 rather than $CumPGuess - $PGuess - * This eliminates a potential endless loop error, but may have an adverse affect on the - * accuracy of the function (although all my tests have so far returned correct results). */ public static function CRITBINOM($trials, $probability, $alpha) { @@ -568,6 +563,11 @@ class Statistical * such as how long an automated bank teller takes to deliver cash. For example, you can * use EXPONDIST to determine the probability that the process takes at most 1 minute. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Exponential::distribution() + * Use the distribution() method in the Statistical\Distributions\Exponential class instead + * * @param float $value Value of the function * @param float $lambda The parameter value * @param bool $cumulative @@ -576,24 +576,7 @@ class Statistical */ public static function EXPONDIST($value, $lambda, $cumulative) { - $value = Functions::flattenSingleValue($value); - $lambda = Functions::flattenSingleValue($lambda); - $cumulative = Functions::flattenSingleValue($cumulative); - - if ((is_numeric($value)) && (is_numeric($lambda))) { - if (($value < 0) || ($lambda < 0)) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 1 - exp(0 - $value * $lambda); - } - - return $lambda * exp(0 - $value * $lambda); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Exponential::distribution($value, $lambda, $cumulative); } /** @@ -604,6 +587,11 @@ class Statistical * For example, you can examine the test scores of men and women entering high school, and determine * if the variability in the females is different from that found in the males. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\F::distribution() + * Use the distribution() method in the Statistical\Distributions\Exponential class instead + * * @param float $value Value of the function * @param int $u The numerator degrees of freedom * @param int $v The denominator degrees of freedom @@ -614,34 +602,7 @@ class Statistical */ public static function FDIST2($value, $u, $v, $cumulative) { - $value = Functions::flattenSingleValue($value); - $u = Functions::flattenSingleValue($u); - $v = Functions::flattenSingleValue($v); - $cumulative = Functions::flattenSingleValue($cumulative); - - if (is_numeric($value) && is_numeric($u) && is_numeric($v)) { - if ($value < 0 || $u < 1 || $v < 1) { - return Functions::NAN(); - } - - $cumulative = (bool) $cumulative; - $u = (int) $u; - $v = (int) $v; - - if ($cumulative) { - $adjustedValue = ($u * $value) / ($u * $value + $v); - - return Statistical\Distributions\Beta::incompleteBeta($adjustedValue, $u / 2, $v / 2); - } - - return (Statistical\Distributions\Gamma::gammaValue(($v + $u) / 2) / - (Statistical\Distributions\Gamma::gammaValue($u / 2) * - Statistical\Distributions\Gamma::gammaValue($v / 2))) * - (($u / $v) ** ($u / 2)) * - (($value ** (($u - 2) / 2)) / ((1 + ($u / $v) * $value) ** (($u + $v) / 2))); - } - - return Functions::VALUE(); + return Statistical\Distributions\F::distribution($value, $u, $v, $cumulative); } /** @@ -908,42 +869,26 @@ class Statistical * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of * sample successes, given the sample size, population successes, and population size. * - * @param float $sampleSuccesses Number of successes in the sample - * @param float $sampleNumber Size of the sample - * @param float $populationSuccesses Number of successes in the population - * @param float $populationNumber Population size + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\HyperGeometric::distribution() + * Use the distribution() method in the Statistical\Distributions\HyperGeometric class instead + * + * @param mixed (int) $sampleSuccesses Number of successes in the sample + * @param mixed (int) $sampleNumber Size of the sample + * @param mixed (int) $populationSuccesses Number of successes in the population + * @param mixed (int) $populationNumber Population size * * @return float|string */ public static function HYPGEOMDIST($sampleSuccesses, $sampleNumber, $populationSuccesses, $populationNumber) { - $sampleSuccesses = Functions::flattenSingleValue($sampleSuccesses); - $sampleNumber = Functions::flattenSingleValue($sampleNumber); - $populationSuccesses = Functions::flattenSingleValue($populationSuccesses); - $populationNumber = Functions::flattenSingleValue($populationNumber); - - if ((is_numeric($sampleSuccesses)) && (is_numeric($sampleNumber)) && (is_numeric($populationSuccesses)) && (is_numeric($populationNumber))) { - $sampleSuccesses = floor($sampleSuccesses); - $sampleNumber = floor($sampleNumber); - $populationSuccesses = floor($populationSuccesses); - $populationNumber = floor($populationNumber); - - if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) { - return Functions::NAN(); - } - if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) { - return Functions::NAN(); - } - if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) { - return Functions::NAN(); - } - - return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) * - MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) / - MathTrig::COMBIN($populationNumber, $sampleNumber); - } - - return Functions::VALUE(); + return Statistical\Distributions\HyperGeometric::distribution( + $sampleSuccesses, + $sampleNumber, + $populationSuccesses, + $populationNumber + ); } /** @@ -2148,8 +2093,10 @@ class Statistical /** * ZTEST. * - * Returns the Weibull distribution. Use this distribution in reliability - * analysis, such as calculating a device's mean time to failure. + * Returns the one-tailed P-value of a z-test. + * + * For a given hypothesized population mean, x, Z.TEST returns the probability that the sample mean would be + * greater than the average of observations in the data set (array) — that is, the observed sample mean. * * @param float $dataSet * @param float $m0 Alpha Parameter diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php new file mode 100644 index 00000000..fe76816d --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php @@ -0,0 +1,49 @@ +getMessage(); + } + + if (($value < 0) || ($lambda < 0)) { + return Functions::NAN(); + } + + if ($cumulative === true) { + return 1 - exp(0 - $value * $lambda); + } + + return $lambda * exp(0 - $value * $lambda); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php new file mode 100644 index 00000000..84456873 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php @@ -0,0 +1,59 @@ +getMessage(); + } + + if ($value < 0 || $u < 1 || $v < 1) { + return Functions::NAN(); + } + + if ($cumulative) { + $adjustedValue = ($u * $value) / ($u * $value + $v); + + return Beta::incompleteBeta($adjustedValue, $u / 2, $v / 2); + } + + return (Gamma::gammaValue(($v + $u) / 2) / + (Gamma::gammaValue($u / 2) * Gamma::gammaValue($v / 2))) * + (($u / $v) ** ($u / 2)) * + (($value ** (($u - 2) / 2)) / ((1 + ($u / $v) * $value) ** (($u + $v) / 2))); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php new file mode 100644 index 00000000..e9848ed4 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php @@ -0,0 +1,56 @@ +getMessage(); + } + + if (($sampleSuccesses < 0) || ($sampleSuccesses > $sampleNumber) || ($sampleSuccesses > $populationSuccesses)) { + return Functions::NAN(); + } + if (($sampleNumber <= 0) || ($sampleNumber > $populationNumber)) { + return Functions::NAN(); + } + if (($populationSuccesses <= 0) || ($populationSuccesses > $populationNumber)) { + return Functions::NAN(); + } + + return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) * + MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) / + MathTrig::COMBIN($populationNumber, $sampleNumber); + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDist2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php similarity index 70% rename from tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDist2Test.php rename to tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php index a6e34429..525247f6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDist2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php @@ -5,21 +5,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical; use PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PHPUnit\Framework\TestCase; -class FDist2Test extends TestCase +class FDistTest extends TestCase { /** - * @dataProvider providerFDIST2 + * @dataProvider providerFDIST * * @param mixed $expectedResult */ - public function testFDIST2($expectedResult, ...$args): void + public function testFDIST($expectedResult, ...$args): void { $result = Statistical::FDIST2(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFDIST2(): array + public function providerFDIST(): array { - return require 'tests/data/Calculation/Statistical/FDIST2.php'; + return require 'tests/data/Calculation/Statistical/FDIST.php'; } } diff --git a/tests/data/Calculation/Statistical/EXPONDIST.php b/tests/data/Calculation/Statistical/EXPONDIST.php index df150e19..fda340db 100644 --- a/tests/data/Calculation/Statistical/EXPONDIST.php +++ b/tests/data/Calculation/Statistical/EXPONDIST.php @@ -1,6 +1,14 @@ Date: Thu, 1 Apr 2021 13:25:05 +0200 Subject: [PATCH 149/187] Resolution for [#Issue 1972](https://github.com/PHPOffice/PhpSpreadsheet/issues/1972) (#1978) * Resolution for [#Issue 1972](https://github.com/PHPOffice/PhpSpreadsheet/issues/1972) where format masks with a leading and trailing quote were always treated as literal strings, even when they masks containing quoted characters. Also resolves issue with colour name case-sensitivity --- CHANGELOG.md | 1 + .../Style/NumberFormat/Formatter.php | 4 +-- tests/data/Style/NumberFormat.php | 31 +++++++++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb3ab111..69d1652a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fixed issue with quoted strings in number format mask rendered with toFormattedString() [Issue 1972#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1972) [PR #1978](https://github.com/PHPOffice/PhpSpreadsheet/pull/1978) - Fixed issue with percentage formats in number format mask rendered with toFormattedString() [Issue 1929#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1929) [PR #1928](https://github.com/PHPOffice/PhpSpreadsheet/pull/1928) - Fixed issue with _ spacing character in number format mask corrupting output from toFormattedString() [Issue 1924#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1924) [PR #1927](https://github.com/PHPOffice/PhpSpreadsheet/pull/1927) - Fix for [Issue #1887](https://github.com/PHPOffice/PhpSpreadsheet/issues/1887) - Lose Track of Selected Cells After Save diff --git a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php index 6fa43fe2..ef756d7b 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/Formatter.php @@ -43,7 +43,7 @@ class Formatter // 3 sections: [POSITIVE/TEXT] [NEGATIVE] [ZERO] // 4 sections: [POSITIVE] [NEGATIVE] [ZERO] [TEXT] $cnt = count($sections); - $color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . ')\\]/'; + $color_regex = '/\\[(' . implode('|', Color::NAMED_COLORS) . ')\\]/mui'; $cond_regex = '/\\[(>|>=|<|<=|=|<>)([+-]?\\d+([.]\\d+)?)\\]/'; $colors = ['', '', '', '', '']; $condops = ['', '', '', '', '']; @@ -139,7 +139,7 @@ class Formatter // datetime format $value = DateFormatter::format($value, $format); } else { - if (substr($format, 0, 1) === '"' && substr($format, -1, 1) === '"') { + if (substr($format, 0, 1) === '"' && substr($format, -1, 1) === '"' && substr_count($format, '"') === 2) { $value = substr($format, 1, -1); } elseif (preg_match('/[0#, ]%/', $format)) { // % number format diff --git a/tests/data/Style/NumberFormat.php b/tests/data/Style/NumberFormat.php index f9db1732..aee357a7 100644 --- a/tests/data/Style/NumberFormat.php +++ b/tests/data/Style/NumberFormat.php @@ -390,6 +390,11 @@ return [ 12345, '[Green]General', ], + [ + '12345', + 12345, + '[GrEeN]General', + ], [ '-70', -70, @@ -404,14 +409,24 @@ return [ [ '12345', 12345, - '[Blue]0;[Red]0', + '[Blue]0;[Red]0-', ], + [ + '12345-', + -12345, + '[BLUE]0;[red]0-', + ], + [ + '12345-', + -12345, + '[blue]0;[RED]0-', + ], + // Multiple colors with text substitution [ 'Positive', 12, '[Green]"Positive";[Red]"Negative";[Blue]"Zero"', ], - // Multiple colors with text substitution [ 'Zero', 0, @@ -422,6 +437,7 @@ return [ -2, '[Green]"Positive";[Red]"Negative";[Blue]"Zero"', ], + // Value break points [ '<=3500 red', 3500, @@ -442,6 +458,17 @@ return [ 25, '[Green][<>25]"<>25 green";[Red]"else red"', ], + // Leading/trailing quotes in mask + [ + '$12.34 ', + 12.34, + '$#,##0.00_;[RED]"($"#,##0.00")"', + ], + [ + '($12.34)', + -12.34, + '$#,##0.00_;[RED]"($"#,##0.00")"', + ], [ 'pfx. 25.00', 25, From a4982fd9fedc392d8aaa2e90161eebfc9ff43b4b Mon Sep 17 00:00:00 2001 From: oleibman Date: Fri, 2 Apr 2021 05:35:34 -0700 Subject: [PATCH 150/187] Continue MathTrig Breakup - Penultimate? (#1973) * Continue MathTrig Breakup - Penultimate? Continuing the process of breaking MathTrip.php up into smaller classes. This round takes care of about half of what is left, so perhaps one round after this one will finish the job: - ARABIC - COMBIN; also implemented COMBINA - FACTDOUBLE - GCD (which accepts and ignores empty cells as arguments, but returns VALUE if all the arguments are that way; LCM does the same) - LOG_BASE, LOG10, LN - implemented MUNIT - MOD - POWER - RAND, RANDBETWEEN (RANDARRAY is too complicated to implement with this ticket) As you can see from the description, there are some functions which were combined in a single class. When not combined, I adopted PowerKiki's suggestion of using "execute" as the function name. Co-authored-by: Mark Baker --- .../Calculation/Calculation.php | 26 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 223 +++--------------- .../Calculation/MathTrig/Arabic.php | 95 ++++++++ .../Calculation/MathTrig/Combinations.php | 74 ++++++ .../Calculation/MathTrig/FactDouble.php | 39 +++ .../Calculation/MathTrig/Gcd.php | 69 ++++++ .../Calculation/MathTrig/Helpers.php | 18 +- .../Calculation/MathTrig/Lcm.php | 33 ++- .../Calculation/MathTrig/Logarithms.php | 79 +++++++ .../Calculation/MathTrig/MatrixFunctions.php | 24 ++ .../Calculation/MathTrig/Mod.php | 36 +++ .../Calculation/MathTrig/Power.php | 42 ++++ .../Calculation/MathTrig/Random.php | 39 +++ .../Calculation/functionlist.txt | 2 + .../Functions/MathTrig/ArabicTest.php | 19 +- .../Functions/MathTrig/CombinATest.php | 33 +++ .../Functions/MathTrig/CombinTest.php | 28 ++- .../Functions/MathTrig/FactDoubleTest.php | 19 +- .../Functions/MathTrig/GcdTest.php | 27 ++- .../Calculation/Functions/MathTrig/LnTest.php | 29 +-- .../Functions/MathTrig/Log10Test.php | 29 +-- .../Functions/MathTrig/LogTest.php | 32 ++- .../Functions/MathTrig/MMultTest.php | 11 + .../Functions/MathTrig/MUnitTest.php | 23 ++ .../Functions/MathTrig/ModTest.php | 32 ++- .../Functions/MathTrig/MovedFunctionsTest.php | 13 +- .../Functions/MathTrig/PowerTest.php | 32 ++- .../Functions/MathTrig/RandBetweenTest.php | 46 ++++ .../Functions/MathTrig/RandTest.php | 24 ++ tests/data/Calculation/MathTrig/COMBIN.php | 9 + tests/data/Calculation/MathTrig/COMBINA.php | 135 +++++++++++ tests/data/Calculation/MathTrig/GCD.php | 4 + tests/data/Calculation/MathTrig/LCM.php | 2 + tests/data/Calculation/MathTrig/LN.php | 4 +- tests/data/Calculation/MathTrig/LOG.php | 1 + tests/data/Calculation/MathTrig/LOG10.php | 4 +- tests/data/Calculation/MathTrig/MDETERM.php | 30 +-- tests/data/Calculation/MathTrig/MINVERSE.php | 46 ++-- tests/data/Calculation/MathTrig/MOD.php | 9 +- tests/data/Calculation/MathTrig/POWER.php | 2 + .../data/Calculation/MathTrig/RANDBETWEEN.php | 19 ++ 41 files changed, 1089 insertions(+), 372 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/FactDouble.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Gcd.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Mod.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Power.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Random.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php create mode 100644 tests/data/Calculation/MathTrig/COMBINA.php create mode 100644 tests/data/Calculation/MathTrig/RANDBETWEEN.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index ef1be8c2..0538e28f 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -288,7 +288,7 @@ class Calculation ], 'ARABIC' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'ARABIC'], + 'functionCall' => [MathTrig\Arabic::class, 'evaluate'], 'argumentCount' => '1', ], 'AREAS' => [ @@ -555,12 +555,12 @@ class Calculation ], 'COMBIN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'COMBIN'], + 'functionCall' => [MathTrig\Combinations::class, 'withoutRepetition'], 'argumentCount' => '2', ], 'COMBINA' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [MathTrig\Combinations::class, 'withRepetition'], 'argumentCount' => '2', ], 'COMPLEX' => [ @@ -995,7 +995,7 @@ class Calculation ], 'FACTDOUBLE' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'FACTDOUBLE'], + 'functionCall' => [MathTrig\FactDouble::class, 'evaluate'], 'argumentCount' => '1', ], 'FALSE' => [ @@ -1187,7 +1187,7 @@ class Calculation ], 'GCD' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'GCD'], + 'functionCall' => [MathTrig\Gcd::class, 'evaluate'], 'argumentCount' => '1+', ], 'GEOMEAN' => [ @@ -1566,17 +1566,17 @@ class Calculation ], 'LN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinLN'], + 'functionCall' => [MathTrig\Logarithms::class, 'natural'], 'argumentCount' => '1', ], 'LOG' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'logBase'], + 'functionCall' => [MathTrig\Logarithms::class, 'withBase'], 'argumentCount' => '1,2', ], 'LOG10' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinLOG10'], + 'functionCall' => [MathTrig\Logarithms::class, 'base10'], 'argumentCount' => '1', ], 'LOGEST' => [ @@ -1701,7 +1701,7 @@ class Calculation ], 'MOD' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'MOD'], + 'functionCall' => [MathTrig\Mod::class, 'evaluate'], 'argumentCount' => '2', ], 'MODE' => [ @@ -1736,7 +1736,7 @@ class Calculation ], 'MUNIT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [Functions::class, 'DUMMY'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMUnit'], 'argumentCount' => '1', ], 'N' => [ @@ -1973,7 +1973,7 @@ class Calculation ], 'POWER' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'POWER'], + 'functionCall' => [MathTrig\Power::class, 'evaluate'], 'argumentCount' => '2', ], 'PPMT' => [ @@ -2043,7 +2043,7 @@ class Calculation ], 'RAND' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'RAND'], + 'functionCall' => [MathTrig\Random::class, 'randNoArgs'], 'argumentCount' => '0', ], 'RANDARRAY' => [ @@ -2053,7 +2053,7 @@ class Calculation ], 'RANDBETWEEN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'RAND'], + 'functionCall' => [MathTrig\Random::class, 'randBetween'], 'argumentCount' => '2', ], 'RANK' => [ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 1dbc2854..e960d7ef 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -2,22 +2,15 @@ namespace PhpOffice\PhpSpreadsheet\Calculation; -use Exception; - class MathTrig { - private static function strSplit(string $roman): array - { - $rslt = str_split($roman); - - return is_array($rslt) ? $rslt : []; - } - /** * ARABIC. * * Converts a Roman numeral to an Arabic numeral. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Arabic class instead + * * Excel Function: * ARABIC(text) * @@ -27,69 +20,7 @@ class MathTrig */ public static function ARABIC($roman) { - // An empty string should return 0 - $roman = substr(trim(strtoupper((string) Functions::flattenSingleValue($roman))), 0, 255); - if ($roman === '') { - return 0; - } - - // Convert the roman numeral to an arabic number - $negativeNumber = $roman[0] === '-'; - if ($negativeNumber) { - $roman = substr($roman, 1); - } - - try { - $arabic = self::calculateArabic(self::strSplit($roman)); - } catch (Exception $e) { - return Functions::VALUE(); // Invalid character detected - } - - if ($negativeNumber) { - $arabic *= -1; // The number should be negative - } - - return $arabic; - } - - /** - * Recursively calculate the arabic value of a roman numeral. - * - * @param int $sum - * @param int $subtract - * - * @return int - */ - protected static function calculateArabic(array $roman, &$sum = 0, $subtract = 0) - { - $lookup = [ - 'M' => 1000, - 'D' => 500, - 'C' => 100, - 'L' => 50, - 'X' => 10, - 'V' => 5, - 'I' => 1, - ]; - - $numeral = array_shift($roman); - if (!isset($lookup[$numeral])) { - throw new Exception('Invalid character detected'); - } - - $arabic = $lookup[$numeral]; - if (count($roman) > 0 && isset($lookup[$roman[0]]) && $arabic < $lookup[$roman[0]]) { - $subtract += $arabic; - } else { - $sum += ($arabic - $subtract); - $subtract = 0; - } - - if (count($roman) > 0) { - self::calculateArabic($roman, $sum, $subtract); - } - - return $sum; + return MathTrig\Arabic::evaluate($roman); } /** @@ -172,6 +103,8 @@ class MathTrig * Returns the number of combinations for a given number of items. Use COMBIN to * determine the total possible number of groups for a given number of items. * + * @Deprecated 2.0.0 Use the without method in the MathTrig\Combinations class instead + * * Excel Function: * COMBIN(numObjs,numInSet) * @@ -182,20 +115,7 @@ class MathTrig */ public static function COMBIN($numObjs, $numInSet) { - $numObjs = Functions::flattenSingleValue($numObjs); - $numInSet = Functions::flattenSingleValue($numInSet); - - if ((is_numeric($numObjs)) && (is_numeric($numInSet))) { - if ($numObjs < $numInSet) { - return Functions::NAN(); - } elseif ($numInSet < 0) { - return Functions::NAN(); - } - - return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)) / MathTrig\Fact::funcFact($numInSet); - } - - return Functions::VALUE(); + return MathTrig\Combinations::withoutRepetition($numObjs, $numInSet); } /** @@ -256,6 +176,8 @@ class MathTrig * * Returns the double factorial of a number. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\FactDouble class instead + * * Excel Function: * FACTDOUBLE(factVal) * @@ -265,23 +187,7 @@ class MathTrig */ public static function FACTDOUBLE($factVal) { - $factLoop = Functions::flattenSingleValue($factVal); - - if (is_numeric($factLoop)) { - $factLoop = floor($factLoop); - if ($factVal < 0) { - return Functions::NAN(); - } - $factorial = 1; - while ($factLoop > 1) { - $factorial *= $factLoop--; - --$factLoop; - } - - return $factorial; - } - - return Functions::VALUE(); + return MathTrig\FactDouble::evaluate($factVal); } /** @@ -351,11 +257,6 @@ class MathTrig return MathTrig\FloorPrecise::funcFloorPrecise($number, $significance); } - private static function evaluateGCD($a, $b) - { - return $b ? self::evaluateGCD($b, $a % $b) : $a; - } - /** * INT. * @@ -384,6 +285,8 @@ class MathTrig * The greatest common divisor is the largest integer that divides both * number1 and number2 without a remainder. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Gcd class instead + * * Excel Function: * GCD(number1[,number2[, ...]]) * @@ -393,22 +296,7 @@ class MathTrig */ public static function GCD(...$args) { - $args = Functions::flattenArray($args); - // Loop through arguments - foreach (Functions::flattenArray($args) as $value) { - if (!is_numeric($value)) { - return Functions::VALUE(); - } elseif ($value < 0) { - return Functions::NAN(); - } - } - - $gcd = (int) array_pop($args); - do { - $gcd = self::evaluateGCD($gcd, (int) array_pop($args)); - } while (!empty($args)); - - return $gcd; + return MathTrig\Gcd::evaluate(...$args); } /** @@ -438,6 +326,8 @@ class MathTrig * * Returns the logarithm of a number to a specified base. The default base is 10. * + * @Deprecated 2.0.0 Use the withBase method in the MathTrig\Logarithms class instead + * * Excel Function: * LOG(number[,base]) * @@ -446,19 +336,9 @@ class MathTrig * * @return float|string The result, or a string containing an error */ - public static function logBase($number = null, $base = 10) + public static function logBase($number, $base = 10) { - $number = Functions::flattenSingleValue($number); - $base = ($base === null) ? 10 : (float) Functions::flattenSingleValue($base); - - if ((!is_numeric($base)) || (!is_numeric($number))) { - return Functions::VALUE(); - } - if (($base <= 0) || ($number <= 0)) { - return Functions::NAN(); - } - - return log($number, $base); + return MathTrig\Logarithms::withBase($number, $base); } /** @@ -517,6 +397,8 @@ class MathTrig /** * MOD. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Mod class instead + * * @param int $a Dividend * @param int $b Divisor * @@ -524,18 +406,7 @@ class MathTrig */ public static function MOD($a = 1, $b = 1) { - $a = (float) Functions::flattenSingleValue($a); - $b = (float) Functions::flattenSingleValue($b); - - if ($b == 0.0) { - return Functions::DIV0(); - } elseif (($a < 0.0) && ($b > 0.0)) { - return $b - fmod(abs($a), $b); - } elseif (($a > 0.0) && ($b < 0.0)) { - return $b + fmod($a, abs($b)); - } - - return fmod($a, $b); + return MathTrig\Mod::evaluate($a, $b); } /** @@ -562,6 +433,8 @@ class MathTrig * * Returns the ratio of the factorial of a sum of values to the product of factorials. * + * @Deprecated 2.0.0 Use the funcMultinomial method in the MathTrig\Multinomial class instead + * * @param mixed[] $args An array of mixed values for the Data Series * * @return float|string The result, or a string containing an error @@ -592,27 +465,16 @@ class MathTrig * * Computes x raised to the power y. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Power class instead + * * @param float $x * @param float $y * - * @return float|string The result, or a string containing an error + * @return float|int|string The result, or a string containing an error */ public static function POWER($x = 0, $y = 2) { - $x = Functions::flattenSingleValue($x); - $y = Functions::flattenSingleValue($y); - - // Validate parameters - if ($x == 0.0 && $y == 0.0) { - return Functions::NAN(); - } elseif ($x == 0.0 && $y < 0.0) { - return Functions::DIV0(); - } - - // Return - $result = $x ** $y; - - return (!is_nan($result) && !is_infinite($result)) ? $result : Functions::NAN(); + return MathTrig\Power::evaluate($x, $y); } /** @@ -656,23 +518,18 @@ class MathTrig } /** - * RAND. + * RAND/RANDBETWEEN. + * + * @Deprecated 2.0.0 Use the randNoArg or randBetween method in the MathTrig\Random class instead * * @param int $min Minimal value * @param int $max Maximal value * - * @return int Random number + * @return float|int|string Random number */ public static function RAND($min = 0, $max = 0) { - $min = Functions::flattenSingleValue($min); - $max = Functions::flattenSingleValue($max); - - if ($min == 0 && $max == 0) { - return (mt_rand(0, 10000000)) / 10000000; - } - - return mt_rand($min, $max); + return MathTrig\Random::randBetween($min, $max); } /** @@ -1388,19 +1245,15 @@ class MathTrig * * Returns the result of builtin function log after validating args. * + * @Deprecated 2.0.0 Use the natural method in the MathTrig\Logarithms class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinLN($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return log($number); + return MathTrig\Logarithms::natural($number); } /** @@ -1408,19 +1261,15 @@ class MathTrig * * Returns the result of builtin function log after validating args. * + * @Deprecated 2.0.0 Use the base10 method in the MathTrig\Logarithms class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinLOG10($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return log10($number); + return MathTrig\Logarithms::base10($number); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php b/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php new file mode 100644 index 00000000..320856b9 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php @@ -0,0 +1,95 @@ + 1000, + 'D' => 500, + 'C' => 100, + 'L' => 50, + 'X' => 10, + 'V' => 5, + 'I' => 1, + ]; + + /** + * Recursively calculate the arabic value of a roman numeral. + * + * @param int $sum + * @param int $subtract + * + * @return int + */ + private static function calculateArabic(array $roman, &$sum = 0, $subtract = 0) + { + $numeral = array_shift($roman); + if (!isset(self::ROMAN_LOOKUP[$numeral])) { + throw new Exception('Invalid character detected'); + } + + $arabic = self::ROMAN_LOOKUP[$numeral]; + if (count($roman) > 0 && isset(self::ROMAN_LOOKUP[$roman[0]]) && $arabic < self::ROMAN_LOOKUP[$roman[0]]) { + $subtract += $arabic; + } else { + $sum += ($arabic - $subtract); + $subtract = 0; + } + + if (count($roman) > 0) { + self::calculateArabic($roman, $sum, $subtract); + } + + return $sum; + } + + private static function strSplit(string $roman): array + { + $rslt = str_split($roman); + + return is_array($rslt) ? $rslt : []; + } + + /** + * ARABIC. + * + * Converts a Roman numeral to an Arabic numeral. + * + * Excel Function: + * ARABIC(text) + * + * @param string $roman + * + * @return int|string the arabic numberal contrived from the roman numeral + */ + public static function evaluate($roman) + { + // An empty string should return 0 + $roman = substr(trim(strtoupper((string) Functions::flattenSingleValue($roman))), 0, 255); + if ($roman === '') { + return 0; + } + + // Convert the roman numeral to an arabic number + $negativeNumber = $roman[0] === '-'; + if ($negativeNumber) { + $roman = substr($roman, 1); + } + + try { + $arabic = self::calculateArabic(self::strSplit($roman)); + } catch (Exception $e) { + return Functions::VALUE(); // Invalid character detected + } + + if ($negativeNumber) { + $arabic *= -1; // The number should be negative + } + + return $arabic; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php b/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php new file mode 100644 index 00000000..78b18fc6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Combinations.php @@ -0,0 +1,74 @@ +getMessage(); + } + + return round(Fact::funcFact($numObjs) / Fact::funcFact($numObjs - $numInSet)) / Fact::funcFact($numInSet); + } + + /** + * COMBIN. + * + * Returns the number of combinations for a given number of items. Use COMBIN to + * determine the total possible number of groups for a given number of items. + * + * Excel Function: + * COMBIN(numObjs,numInSet) + * + * @param mixed $numObjs Number of different objects + * @param mixed $numInSet Number of objects in each combination + * + * @return float|int|string Number of combinations, or a string containing an error + */ + public static function withRepetition($numObjs, $numInSet) + { + try { + $numObjs = Helpers::validateNumericNullSubstitution($numObjs, null); + $numInSet = Helpers::validateNumericNullSubstitution($numInSet, null); + Helpers::validateNotNegative($numInSet); + Helpers::validateNotNegative($numObjs); + $numObjs = (int) $numObjs; + $numInSet = (int) $numInSet; + // Microsoft documentation says following is true, but Excel + // does not enforce this restriction. + //Helpers::validateNotNegative($numObjs - $numInSet); + if ($numObjs === 0) { + Helpers::validateNotNegative(-$numInSet); + + return 1; + } + } catch (Exception $e) { + return $e->getMessage(); + } + + return round(Fact::funcFact($numObjs + $numInSet - 1) / Fact::funcFact($numObjs - 1)) / Fact::funcFact($numInSet); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/FactDouble.php b/src/PhpSpreadsheet/Calculation/MathTrig/FactDouble.php new file mode 100644 index 00000000..4b760144 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/FactDouble.php @@ -0,0 +1,39 @@ +getMessage(); + } + + $factLoop = floor($factVal); + $factorial = 1; + while ($factLoop > 1) { + $factorial *= $factLoop; + $factLoop -= 2; + } + + return $factorial; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Gcd.php b/src/PhpSpreadsheet/Calculation/MathTrig/Gcd.php new file mode 100644 index 00000000..21c22699 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Gcd.php @@ -0,0 +1,69 @@ +getMessage(); + } + + if (count($arrayArgs) <= 0) { + return Functions::VALUE(); + } + $gcd = (int) array_pop($arrayArgs); + do { + $gcd = self::evaluateGCD($gcd, (int) array_pop($arrayArgs)); + } while (!empty($arrayArgs)); + + return $gcd; + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php index 7abcf050..26716467 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php @@ -66,13 +66,27 @@ class Helpers * * @param float|int $number */ - public static function validateNotNegative($number): void + public static function validateNotNegative($number, ?string $except = null): void { if ($number >= 0) { return; } - throw new Exception(Functions::NAN()); + throw new Exception($except ?? Functions::NAN()); + } + + /** + * Confirm number > 0. + * + * @param float|int $number + */ + public static function validatePositive($number, ?string $except = null): void + { + if ($number > 0) { + return; + } + + throw new Exception($except ?? Functions::NAN()); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php b/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php index 3d3f0e46..38d9b620 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php @@ -53,12 +53,15 @@ class Lcm try { $arrayArgs = []; $anyZeros = 0; + $anyNonNulls = 0; foreach (Functions::flattenArray($args) as $value1) { + $anyNonNulls += (int) ($value1 !== null); $value = Helpers::validateNumericNullSubstitution($value1, 1); Helpers::validateNotNegative($value); $arrayArgs[] = (int) $value; $anyZeros += (int) !((bool) $value); } + self::testNonNulls($anyNonNulls); if ($anyZeros) { return 0; } @@ -76,15 +79,7 @@ class Lcm foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) { $myPoweredFactors[$myCountedFactor] = $myCountedFactor ** $myCountedPower; } - foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) { - if (isset($allPoweredFactors[$myPoweredValue])) { - if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) { - $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; - } - } else { - $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; - } - } + self::processPoweredFactors($allPoweredFactors, $myPoweredFactors); } foreach ($allPoweredFactors as $allPoweredFactor) { $returnValue *= (int) $allPoweredFactor; @@ -92,4 +87,24 @@ class Lcm return $returnValue; } + + private static function processPoweredFactors(array &$allPoweredFactors, array &$myPoweredFactors): void + { + foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) { + if (isset($allPoweredFactors[$myPoweredValue])) { + if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) { + $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; + } + } else { + $allPoweredFactors[$myPoweredValue] = $myPoweredFactor; + } + } + } + + private static function testNonNulls(int $anyNonNulls): void + { + if (!$anyNonNulls) { + throw new Exception(Functions::VALUE()); + } + } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php b/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php new file mode 100644 index 00000000..356a0937 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php @@ -0,0 +1,79 @@ +getMessage(); + } + + return log($number, $base); + } + + /** + * LOG10. + * + * Returns the result of builtin function log after validating args. + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function base10($number) + { + try { + $number = Helpers::validateNumericNullBool($number); + Helpers::validatePositive($number); + } catch (Exception $e) { + return $e->getMessage(); + } + + return log10($number); + } + + /** + * LN. + * + * Returns the result of builtin function log after validating args. + * + * @Deprecated 2.0.0 Use the natural method in the MathTrig\Logarithms class instead + * + * @param mixed $number Should be numeric + * + * @return float|string Rounded number + */ + public static function natural($number) + { + try { + $number = Helpers::validateNumericNullBool($number); + Helpers::validatePositive($number); + } catch (Exception $e) { + return $e->getMessage(); + } + + return log($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php b/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php index 77c8b1e1..145adfa0 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig; use Exception; +use Matrix\Builder; use Matrix\Exception as MatrixException; use Matrix\Matrix; use PhpOffice\PhpSpreadsheet\Calculation\Functions; @@ -111,4 +112,27 @@ class MatrixFunctions return $e->getMessage(); } } + + /** + * MUnit. + * + * @param mixed $dimension Number of rows and columns + * + * @return array|string The result, or a string containing an error + */ + public static function funcMUnit($dimension) + { + try { + $dimension = (int) Helpers::validateNumericNullBool($dimension); + Helpers::validatePositive($dimension, Functions::VALUE()); + $matrix = Builder::createFilledMatrix(0, $dimension)->toArray(); + for ($x = 0; $x < $dimension; ++$x) { + $matrix[$x][$x] = 1; + } + + return $matrix; + } catch (Exception $e) { + return $e->getMessage(); + } + } } diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php b/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php new file mode 100644 index 00000000..b2e3cf4b --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php @@ -0,0 +1,36 @@ +getMessage(); + } + + if (($a < 0.0) && ($b > 0.0)) { + return $b - fmod(abs($a), $b); + } + if (($a > 0.0) && ($b < 0.0)) { + return $b + fmod($a, abs($b)); + } + + return fmod($a, $b); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Power.php b/src/PhpSpreadsheet/Calculation/MathTrig/Power.php new file mode 100644 index 00000000..70d177cd --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Power.php @@ -0,0 +1,42 @@ +getMessage(); + } + + // Validate parameters + if (!$x && !$y) { + return Functions::NAN(); + } + if (!$x && $y < 0.0) { + return Functions::DIV0(); + } + + // Return + $result = $x ** $y; + + return Helpers::numberOrNan($result); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Random.php b/src/PhpSpreadsheet/Calculation/MathTrig/Random.php new file mode 100644 index 00000000..1a384fe9 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Random.php @@ -0,0 +1,39 @@ +getMessage(); + } + + return mt_rand($min, $max); + } +} diff --git a/src/PhpSpreadsheet/Calculation/functionlist.txt b/src/PhpSpreadsheet/Calculation/functionlist.txt index 96c28a97..270715cd 100644 --- a/src/PhpSpreadsheet/Calculation/functionlist.txt +++ b/src/PhpSpreadsheet/Calculation/functionlist.txt @@ -53,6 +53,7 @@ CODE COLUMN COLUMNS COMBIN +COMBINA COMPLEX CONCAT CONCATENATE @@ -249,6 +250,7 @@ MODE MONTH MROUND MULTINOMIAL +MUNIT N NA NEGBINOMDIST diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php index 7b3a5e15..93ed4f25 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class ArabicTest extends TestCase +class ArabicTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerARABIC * @@ -21,8 +12,12 @@ class ArabicTest extends TestCase */ public function testARABIC($expectedResult, $romanNumeral): void { - $result = MathTrig::ARABIC($romanNumeral); - self::assertEquals($expectedResult, $result); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue($romanNumeral); + $sheet->getCell('B1')->setValue('=ARABIC(A1)'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertSame($expectedResult, $result); } public function providerARABIC() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php new file mode 100644 index 00000000..6ab71c7c --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php @@ -0,0 +1,33 @@ +mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($numObjs !== null) { + $sheet->getCell('A1')->setValue($numObjs); + } + if ($numInSet !== null) { + $sheet->getCell('A2')->setValue($numInSet); + } + $sheet->getCell('B1')->setValue('=COMBINA(A1,A2)'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); + } + + public function providerCOMBINA() + { + return require 'tests/data/Calculation/MathTrig/COMBINA.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php index d9156339..8b2749d8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php @@ -2,26 +2,28 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class CombinTest extends TestCase +class CombinTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerCOMBIN * * @param mixed $expectedResult + * @param mixed $numObjs + * @param mixed $numInSet */ - public function testCOMBIN($expectedResult, ...$args): void + public function testCOMBIN($expectedResult, $numObjs, $numInSet): void { - $result = MathTrig::COMBIN(...$args); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($numObjs !== null) { + $sheet->getCell('A1')->setValue($numObjs); + } + if ($numInSet !== null) { + $sheet->getCell('A2')->setValue($numInSet); + } + $sheet->getCell('B1')->setValue('=COMBIN(A1,A2)'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); } public function providerCOMBIN() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php index f0b6b146..f3627205 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class FactDoubleTest extends TestCase +class FactDoubleTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerFACTDOUBLE * @@ -21,8 +12,12 @@ class FactDoubleTest extends TestCase */ public function testFACTDOUBLE($expectedResult, $value): void { - $result = MathTrig::FACTDOUBLE($value); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $sheet->getCell('A1')->setValue($value); + $sheet->getCell('B1')->setValue('=FACTDOUBLE(A1)'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEquals($expectedResult, $result); } public function providerFACTDOUBLE() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php index ce1aec3f..6d87ccc3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class GcdTest extends TestCase +class GcdTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerGCD * @@ -20,7 +11,21 @@ class GcdTest extends TestCase */ public function testGCD($expectedResult, ...$args): void { - $result = MathTrig::GCD(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $row = 0; + foreach ($args as $arg) { + ++$row; + if ($arg !== null) { + $sheet->getCell("A$row")->setValue($arg); + } + } + if ($row < 1) { + $sheet->getCell('B1')->setValue('=GCD()'); + } else { + $sheet->getCell('B1')->setValue("=GCD(A1:A$row)"); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php index 1910ef02..e4c46017 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php @@ -2,30 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class LnTest extends TestCase +class LnTest extends AllSetupTeardown { /** * @dataProvider providerLN * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testLN($expectedResult, $val = null): void + public function testLN($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=LN()'; - } else { - $formula = "=LN($val)"; + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($number !== null) { + $sheet->getCell('A1')->setValue($number); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=LN()'); + } else { + $sheet->getCell('B1')->setValue('=LN(A1)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php index e537030c..b6afaeda 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php @@ -2,30 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class Log10Test extends TestCase +class Log10Test extends AllSetupTeardown { /** * @dataProvider providerLN * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testLN($expectedResult, $val = null): void + public function testLN($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=LOG10()'; - } else { - $formula = "=LOG10($val)"; + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($number !== null) { + $sheet->getCell('A1')->setValue($number); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=LOG10()'); + } else { + $sheet->getCell('B1')->setValue('=LOG10(A1)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php index 184d83e6..f27ec94a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php @@ -2,25 +2,33 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class LogTest extends TestCase +class LogTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerLOG * * @param mixed $expectedResult + * @param mixed $number + * @param mixed $base */ - public function testLOG($expectedResult, ...$args): void + public function testLOG($expectedResult, $number = 'omitted', $base = 'omitted'): void { - $result = MathTrig::logBase(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($number !== null) { + $sheet->getCell('A1')->setValue($number); + } + if ($base !== null) { + $sheet->getCell('A2')->setValue($base); + } + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=LOG()'); + } elseif ($base === 'omitted') { + $sheet->getCell('B1')->setValue('=LOG(A1)'); + } else { + $sheet->getCell('B1')->setValue('=LOG(A1,A2)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php index ca8ee5d7..6c40103c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php @@ -28,5 +28,16 @@ class MMultTest extends AllSetupTeardown $sheet = $this->sheet; $sheet->getCell('A1')->setValue('=MMULT({1,2,3}, {1,2,3})'); // incompatible dimensions self::assertSame('#VALUE!', $sheet->getCell('A1')->getCalculatedValue()); + + $sheet->getCell('A11')->setValue('=MMULT({1, 2, 3, 4}, {5; 6; 7; 8})'); + self::assertEquals(70, $sheet->getCell('A11')->getCalculatedValue()); + $sheet->getCell('A2')->setValue(1); + $sheet->getCell('B2')->setValue(2); + $sheet->getCell('C2')->setValue(3); + $sheet->getCell('D2')->setValue(4); + $sheet->getCell('D3')->setValue(5); + $sheet->getCell('D4')->setValue(6); + $sheet->getCell('A12')->setValue('=MMULT(A2:C2,D2:D4)'); + self::assertEquals(32, $sheet->getCell('A12')->getCalculatedValue()); } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php new file mode 100644 index 00000000..4e9f95cf --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php @@ -0,0 +1,23 @@ +mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($dividend !== null) { + $sheet->getCell('A1')->setValue($dividend); + } + if ($divisor !== null) { + $sheet->getCell('A2')->setValue($divisor); + } + if ($dividend === 'omitted') { + $sheet->getCell('B1')->setValue('=MOD()'); + } elseif ($divisor === 'omitted') { + $sheet->getCell('B1')->setValue('=MOD(A1)'); + } else { + $sheet->getCell('B1')->setValue('=MOD(A1,A2)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php index 5b3642ff..580092cd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php @@ -20,6 +20,7 @@ class MovedFunctionsTest extends TestCase self::assertEqualsWithDelta(0, MathTrig::builtinACOSH(1), 1E-9); self::assertEqualsWithDelta(3.04192400109863, MathTrig::ACOT(-10), 1E-9); self::assertEqualsWithDelta(-0.20273255405408, MathTrig::ACOTH(-5), 1E-9); + self::assertSame(49, MathTrig::ARABIC('XLIX')); self::assertEqualsWithDelta(0, MathTrig::builtinASIN(0), 1E-9); self::assertEqualsWithDelta(0, MathTrig::builtinASINH(0), 1E-9); self::assertEqualsWithDelta(0, MathTrig::builtinATAN(0), 1E-9); @@ -27,6 +28,7 @@ class MovedFunctionsTest extends TestCase self::assertEqualsWithDelta('#DIV/0!', MathTrig::ATAN2(0, 0), 1E-9); self::assertEquals('12', MathTrig::BASE(10, 8)); self::assertEquals(-6, MathTrig::CEILING(-4.5, -2)); + self::assertEquals(15, MathTrig::COMBIN(6, 2)); self::assertEquals(1, MathTrig::builtinCOS(0)); self::assertEquals(1, MathTrig::builtinCOSH(0)); self::assertEquals('#DIV/0!', MathTrig::COT(0)); @@ -35,25 +37,32 @@ class MovedFunctionsTest extends TestCase self::assertEquals('#DIV/0!', MathTrig::CSCH(0)); self::assertEquals(6, MathTrig::EVEN(4.5)); self::assertEquals(6, MathTrig::FACT(3)); + self::assertEquals(105, MathTrig::FACTDOUBLE(7)); self::assertEquals(-6, MathTrig::FLOOR(-4.5, 2)); self::assertEquals(0.23, MathTrig::FLOORMATH(0.234, 0.01)); self::assertEquals(-4, MathTrig::FLOORPRECISE(-2.5, 2)); self::assertEquals(-9, MathTrig::INT(-8.3)); self::assertEquals(12, MathTrig::LCM(4, 6)); + self::assertEqualswithDelta(2.302585, MathTrig::builtinLN(10), 1E-6); + self::assertEqualswithDelta(0.306762486567556, MathTrig::logBase(1.5, 3.75), 1E-6); + self::assertEqualswithDelta(0.301030, MathTrig::builtinLOG10(2), 1E-6); self::assertEquals(1, MathTrig::MDETERM([1])); self::assertEquals( [[2, 2], [2, 1]], - MathTrig::MINVERSE([[-0.5, 1.0], [1.0, -1.0]]) + MathTrig::MINVERSE([[-0.5, 1.0], [1.0, -1.0]]) ); self::assertEquals( [[23], [53]], - MathTrig::MMULT([[1, 2], [3, 4]], [[7], [8]]) + MathTrig::MMULT([[1, 2], [3, 4]], [[7], [8]]) ); + self::assertEquals(1, MathTrig::MOD(5, 2)); self::assertEquals(6, MathTrig::MROUND(7.3, 3)); self::assertEquals(1, MathTrig::MULTINOMIAL(1)); self::assertEquals(5, MathTrig::ODD(4.5)); + self::assertEquals(8, MathTrig::POWER(2, 3)); self::assertEquals(8, MathTrig::PRODUCT(1, 2, 4)); self::assertEquals(8, MathTrig::QUOTIENT(17, 2)); + self::assertGreaterThanOrEqual(0, MATHTRIG::RAND()); self::assertEquals('I', MathTrig::ROMAN(1)); self::assertEquals(3.3, MathTrig::builtinROUND(3.27, 1)); self::assertEquals(662, MathTrig::ROUNDDOWN(662.79, 0)); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php index 6749b14a..f68941b8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php @@ -2,25 +2,33 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class PowerTest extends TestCase +class PowerTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerPOWER * * @param mixed $expectedResult + * @param mixed $base + * @param mixed $exponent */ - public function testPOWER($expectedResult, ...$args): void + public function testPOWER($expectedResult, $base = 'omitted', $exponent = 'omitted'): void { - $result = MathTrig::POWER(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($base !== null) { + $sheet->getCell('A1')->setValue($base); + } + if ($exponent !== null) { + $sheet->getCell('A2')->setValue($exponent); + } + if ($base === 'omitted') { + $sheet->getCell('B1')->setValue('=POWER()'); + } elseif ($exponent === 'omitted') { + $sheet->getCell('B1')->setValue('=POWER(A1)'); + } else { + $sheet->getCell('B1')->setValue('=POWER(A1,A2)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php new file mode 100644 index 00000000..0efe8ba6 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php @@ -0,0 +1,46 @@ +mightHaveException($expectedResult); + $sheet = $this->sheet; + $lower = (int) $min; + $upper = (int) $max; + if ($min !== null) { + $sheet->getCell('A1')->setValue($min); + } + if ($max !== null) { + $sheet->getCell('A2')->setValue($max); + } + if ($min === 'omitted') { + $sheet->getCell('B1')->setValue('=RANDBETWEEN()'); + } elseif ($max === 'omitted') { + $sheet->getCell('B1')->setValue('=RANDBETWEEN(A1)'); + } else { + $sheet->getCell('B1')->setValue('=RANDBETWEEN(A1,A2)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); + if (is_numeric($expectedResult)) { + self::assertGreaterThanOrEqual($lower, $result); + self::assertLessThanOrEqual($upper, $result); + } else { + self::assertSame($expectedResult, $result); + } + } + + public function providerRANDBETWEEN() + { + return require 'tests/data/Calculation/MathTrig/RANDBETWEEN.php'; + } +} diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php new file mode 100644 index 00000000..e5e2e107 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php @@ -0,0 +1,24 @@ +sheet; + $sheet->getCell('B1')->setValue('=RAND()'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertGreaterThanOrEqual(0, $result); + self::assertLessThanOrEqual(1, $result); + } + + public function testRandException(): void + { + $this->mightHaveException('exception'); + $sheet = $this->sheet; + $sheet->getCell('B1')->setValue('=RAND(A1)'); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEquals(0, $result); + } +} diff --git a/tests/data/Calculation/MathTrig/COMBIN.php b/tests/data/Calculation/MathTrig/COMBIN.php index f5e36a75..d163e883 100644 --- a/tests/data/Calculation/MathTrig/COMBIN.php +++ b/tests/data/Calculation/MathTrig/COMBIN.php @@ -71,6 +71,11 @@ return [ [ '#VALUE!', 'ABCD', + 2, + ], + [ + '#VALUE!', + 3, 'EFGH', ], [ @@ -123,4 +128,8 @@ return [ 6, 7, ], + [1, 0, 0], + ['#NUM!', 0, 1], + ['#VALUE!', 1, true], + ['#VALUE!', 1, null], ]; diff --git a/tests/data/Calculation/MathTrig/COMBINA.php b/tests/data/Calculation/MathTrig/COMBINA.php new file mode 100644 index 00000000..c5a26a5f --- /dev/null +++ b/tests/data/Calculation/MathTrig/COMBINA.php @@ -0,0 +1,135 @@ + Date: Fri, 2 Apr 2021 20:17:03 +0200 Subject: [PATCH 151/187] Extract Normal and Standard Normal Distributions from the Statistical Class (#1981) * Extract Normal and Standard Normal Distributions from the Statistical Class * Extract ZTest from the Statistical Class, and move it to the Standard Normal Distribution class Additional unit tests for NORMINV() * Extract LogNormal distribution functions from Statistical --- .../Calculation/Calculation.php | 28 +- .../Calculation/Statistical.php | 245 ++++-------------- .../Calculation/Statistical/Confidence.php | 3 +- .../Statistical/Distributions/LogNormal.php | 121 +++++++++ .../Statistical/Distributions/Normal.php | 168 ++++++++++++ .../Distributions/StandardNormal.php | 89 +++++++ .../Functions/Statistical/NormInvTest.php | 2 +- .../Functions/Statistical/ZTestTest.php | 28 ++ tests/data/Calculation/Statistical/LOGINV.php | 18 +- .../Calculation/Statistical/LOGNORMDIST.php | 8 +- .../Calculation/Statistical/LOGNORMDIST2.php | 9 +- .../data/Calculation/Statistical/NORMDIST.php | 5 +- .../data/Calculation/Statistical/NORMINV.php | 6 +- .../Calculation/Statistical/NORMSDIST.php | 2 +- .../Calculation/Statistical/NORMSDIST2.php | 3 +- .../data/Calculation/Statistical/NORMSINV.php | 3 + tests/data/Calculation/Statistical/ZTEST.php | 42 +++ 17 files changed, 563 insertions(+), 217 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php create mode 100644 tests/data/Calculation/Statistical/ZTEST.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 0538e28f..967d05e5 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1586,22 +1586,22 @@ class Calculation ], 'LOGINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'LOGINV'], + 'functionCall' => [Statistical\Distributions\LogNormal::class, 'inverse'], 'argumentCount' => '3', ], 'LOGNORMDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'LOGNORMDIST'], + 'functionCall' => [Statistical\Distributions\LogNormal::class, 'cumulative'], 'argumentCount' => '3', ], 'LOGNORM.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'LOGNORMDIST2'], + 'functionCall' => [Statistical\Distributions\LogNormal::class, 'distribution'], 'argumentCount' => '4', ], 'LOGNORM.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'LOGINV'], + 'functionCall' => [Statistical\Distributions\LogNormal::class, 'inverse'], 'argumentCount' => '3', ], 'LOOKUP' => [ @@ -1776,42 +1776,42 @@ class Calculation ], 'NORMDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMDIST'], + 'functionCall' => [Statistical\Distributions\Normal::class, 'distribution'], 'argumentCount' => '4', ], 'NORM.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMDIST'], + 'functionCall' => [Statistical\Distributions\Normal::class, 'distribution'], 'argumentCount' => '4', ], 'NORMINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMINV'], + 'functionCall' => [Statistical\Distributions\Normal::class, 'inverse'], 'argumentCount' => '3', ], 'NORM.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMINV'], + 'functionCall' => [Statistical\Distributions\Normal::class, 'inverse'], 'argumentCount' => '3', ], 'NORMSDIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMSDIST'], + 'functionCall' => [Statistical\Distributions\StandardNormal::class, 'cumulative'], 'argumentCount' => '1', ], 'NORM.S.DIST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMSDIST2'], + 'functionCall' => [Statistical\Distributions\StandardNormal::class, 'distribution'], 'argumentCount' => '1,2', ], 'NORMSINV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMSINV'], + 'functionCall' => [Statistical\Distributions\StandardNormal::class, 'inverse'], 'argumentCount' => '1', ], 'NORM.S.INV' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'NORMSINV'], + 'functionCall' => [Statistical\Distributions\StandardNormal::class, 'inverse'], 'argumentCount' => '1', ], 'NOT' => [ @@ -2651,12 +2651,12 @@ class Calculation ], 'ZTEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'ZTEST'], + 'functionCall' => [Statistical\Distributions\StandardNormal::class, 'zTest'], 'argumentCount' => '2-3', ], 'Z.TEST' => [ 'category' => Category::CATEGORY_STATISTICAL, - 'functionCall' => [Statistical::class, 'ZTEST'], + 'functionCall' => [Statistical\Distributions\StandardNormal::class, 'zTest'], 'argumentCount' => '2-3', ], ]; diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 1576af98..3e90b21d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -21,90 +21,6 @@ class Statistical const MAX_ITERATIONS = 256; const SQRT2PI = 2.5066282746310005024157652848110452530069867406099; - /* - * inverse_ncdf.php - * ------------------- - * begin : Friday, January 16, 2004 - * copyright : (C) 2004 Michael Nickerson - * email : nickersonm@yahoo.com - * - */ - private static function inverseNcdf($p) - { - // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to - // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as - // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html - // I have not checked the accuracy of this implementation. Be aware that PHP - // will truncate the coeficcients to 14 digits. - - // You have permission to use and distribute this function freely for - // whatever purpose you want, but please show common courtesy and give credit - // where credit is due. - - // Input paramater is $p - probability - where 0 < p < 1. - - // Coefficients in rational approximations - static $a = [ - 1 => -3.969683028665376e+01, - 2 => 2.209460984245205e+02, - 3 => -2.759285104469687e+02, - 4 => 1.383577518672690e+02, - 5 => -3.066479806614716e+01, - 6 => 2.506628277459239e+00, - ]; - - static $b = [ - 1 => -5.447609879822406e+01, - 2 => 1.615858368580409e+02, - 3 => -1.556989798598866e+02, - 4 => 6.680131188771972e+01, - 5 => -1.328068155288572e+01, - ]; - - static $c = [ - 1 => -7.784894002430293e-03, - 2 => -3.223964580411365e-01, - 3 => -2.400758277161838e+00, - 4 => -2.549732539343734e+00, - 5 => 4.374664141464968e+00, - 6 => 2.938163982698783e+00, - ]; - - static $d = [ - 1 => 7.784695709041462e-03, - 2 => 3.224671290700398e-01, - 3 => 2.445134137142996e+00, - 4 => 3.754408661907416e+00, - ]; - - // Define lower and upper region break-points. - $p_low = 0.02425; //Use lower region approx. below this - $p_high = 1 - $p_low; //Use upper region approx. above this - - if (0 < $p && $p < $p_low) { - // Rational approximation for lower region. - $q = sqrt(-2 * log($p)); - - return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / - (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); - } elseif ($p_low <= $p && $p <= $p_high) { - // Rational approximation for central region. - $q = $p - 0.5; - $r = $q * $q; - - return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q / - ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1); - } elseif ($p_high < $p && $p < 1) { - // Rational approximation for upper region. - $q = sqrt(-2 * log(1 - $p)); - - return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / - (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); - } - // If 0 < p < 1, return a null value - return Functions::NULL(); - } - /** * AVEDEV. * @@ -766,7 +682,7 @@ class Statistical return Functions::VALUE(); } - return self::NORMDIST($value, 0, 1, true) - 0.5; + return Statistical\Distributions\Normal::distribution($value, 0, 1, true) - 0.5; } /** @@ -1048,6 +964,11 @@ class Statistical * * Returns the inverse of the normal cumulative distribution * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\LogNormal::inverse() + * Use the inverse() method in the Statistical\Distributions\LogNormal class instead + * * @param float $probability * @param float $mean * @param float $stdDev @@ -1060,19 +981,7 @@ class Statistical */ public static function LOGINV($probability, $mean, $stdDev) { - $probability = Functions::flattenSingleValue($probability); - $mean = Functions::flattenSingleValue($mean); - $stdDev = Functions::flattenSingleValue($stdDev); - - if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($probability < 0) || ($probability > 1) || ($stdDev <= 0)) { - return Functions::NAN(); - } - - return exp($mean + $stdDev * self::NORMSINV($probability)); - } - - return Functions::VALUE(); + return Statistical\Distributions\LogNormal::inverse($probability, $mean, $stdDev); } /** @@ -1081,6 +990,11 @@ class Statistical * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed * with parameters mean and standard_dev. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\LogNormal::cumulative() + * Use the cumulative() method in the Statistical\Distributions\LogNormal class instead + * * @param float $value * @param float $mean * @param float $stdDev @@ -1089,19 +1003,7 @@ class Statistical */ public static function LOGNORMDIST($value, $mean, $stdDev) { - $value = Functions::flattenSingleValue($value); - $mean = Functions::flattenSingleValue($mean); - $stdDev = Functions::flattenSingleValue($stdDev); - - if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($value <= 0) || ($stdDev <= 0)) { - return Functions::NAN(); - } - - return self::NORMSDIST((log($value) - $mean) / $stdDev); - } - - return Functions::VALUE(); + return Statistical\Distributions\LogNormal::cumulative($value, $mean, $stdDev); } /** @@ -1110,6 +1012,11 @@ class Statistical * Returns the lognormal distribution of x, where ln(x) is normally distributed * with parameters mean and standard_dev. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\LogNormal::distribution() + * Use the distribution() method in the Statistical\Distributions\LogNormal class instead + * * @param float $value * @param float $mean * @param float $stdDev @@ -1119,25 +1026,7 @@ class Statistical */ public static function LOGNORMDIST2($value, $mean, $stdDev, $cumulative = false) { - $value = Functions::flattenSingleValue($value); - $mean = Functions::flattenSingleValue($mean); - $stdDev = Functions::flattenSingleValue($stdDev); - $cumulative = (bool) Functions::flattenSingleValue($cumulative); - - if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($value <= 0) || ($stdDev <= 0)) { - return Functions::NAN(); - } - - if ($cumulative === true) { - return self::NORMSDIST2((log($value) - $mean) / $stdDev, true); - } - - return (1 / (sqrt(2 * M_PI) * $stdDev * $value)) * - exp(0 - ((log($value) - $mean) ** 2 / (2 * $stdDev ** 2))); - } - - return Functions::VALUE(); + return Statistical\Distributions\LogNormal::distribution($value, $mean, $stdDev, $cumulative); } /** @@ -1329,7 +1218,7 @@ class Statistical * * @Deprecated 1.18.0 * - * @see Statistical\Distributions\Binomial::negative::mode() + * @see Statistical\Distributions\Binomial::negative() * Use the negative() method in the Statistical\Distributions\Binomial class instead * * @param mixed (float) $failures Number of Failures @@ -1350,6 +1239,11 @@ class Statistical * function has a very wide range of applications in statistics, including hypothesis * testing. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Normal::distribution() + * Use the distribution() method in the Statistical\Distributions\Normal class instead + * * @param mixed (float) $value * @param mixed (float) $mean Mean Value * @param mixed (float) $stdDev Standard Deviation @@ -1359,24 +1253,7 @@ class Statistical */ public static function NORMDIST($value, $mean, $stdDev, $cumulative) { - $value = Functions::flattenSingleValue($value); - $mean = Functions::flattenSingleValue($mean); - $stdDev = Functions::flattenSingleValue($stdDev); - - if ((is_numeric($value)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if ($stdDev < 0) { - return Functions::NAN(); - } - if ((is_numeric($cumulative)) || (is_bool($cumulative))) { - if ($cumulative) { - return 0.5 * (1 + Engineering\Erf::erfValue(($value - $mean) / ($stdDev * sqrt(2)))); - } - - return (1 / (self::SQRT2PI * $stdDev)) * exp(0 - (($value - $mean) ** 2 / (2 * ($stdDev * $stdDev)))); - } - } - - return Functions::VALUE(); + return Statistical\Distributions\Normal::distribution($value, $mean, $stdDev, $cumulative); } /** @@ -1384,6 +1261,11 @@ class Statistical * * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\Normal::inverse() + * Use the inverse() method in the Statistical\Distributions\Normal class instead + * * @param mixed (float) $probability * @param mixed (float) $mean Mean Value * @param mixed (float) $stdDev Standard Deviation @@ -1392,22 +1274,7 @@ class Statistical */ public static function NORMINV($probability, $mean, $stdDev) { - $probability = Functions::flattenSingleValue($probability); - $mean = Functions::flattenSingleValue($mean); - $stdDev = Functions::flattenSingleValue($stdDev); - - if ((is_numeric($probability)) && (is_numeric($mean)) && (is_numeric($stdDev))) { - if (($probability < 0) || ($probability > 1)) { - return Functions::NAN(); - } - if ($stdDev < 0) { - return Functions::NAN(); - } - - return (self::inverseNcdf($probability) * $stdDev) + $mean; - } - - return Functions::VALUE(); + return Statistical\Distributions\Normal::inverse($probability, $mean, $stdDev); } /** @@ -1417,18 +1284,18 @@ class Statistical * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a * table of standard normal curve areas. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\StandardNormal::cumulative() + * Use the cumulative() method in the Statistical\Distributions\StandardNormal class instead + * * @param mixed (float) $value * * @return float|string The result, or a string containing an error */ public static function NORMSDIST($value) { - $value = Functions::flattenSingleValue($value); - if (!is_numeric($value)) { - return Functions::VALUE(); - } - - return self::NORMDIST($value, 0, 1, true); + return Statistical\Distributions\StandardNormal::cumulative($value); } /** @@ -1438,6 +1305,11 @@ class Statistical * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a * table of standard normal curve areas. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\StandardNormal::distribution() + * Use the distribution() method in the Statistical\Distributions\StandardNormal class instead + * * @param mixed (float) $value * @param mixed (bool) $cumulative * @@ -1445,13 +1317,7 @@ class Statistical */ public static function NORMSDIST2($value, $cumulative) { - $value = Functions::flattenSingleValue($value); - if (!is_numeric($value)) { - return Functions::VALUE(); - } - $cumulative = (bool) Functions::flattenSingleValue($cumulative); - - return self::NORMDIST($value, 0, 1, $cumulative); + return Statistical\Distributions\StandardNormal::distribution($value, $cumulative); } /** @@ -1459,13 +1325,18 @@ class Statistical * * Returns the inverse of the standard normal cumulative distribution * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\StandardNormal::inverse() + * Use the inverse() method in the Statistical\Distributions\StandardNormal class instead + * * @param mixed (float) $value * * @return float|string The result, or a string containing an error */ public static function NORMSINV($value) { - return self::NORMINV($value, 0, 1); + return Statistical\Distributions\StandardNormal::inverse($value); } /** @@ -2098,6 +1969,11 @@ class Statistical * For a given hypothesized population mean, x, Z.TEST returns the probability that the sample mean would be * greater than the average of observations in the data set (array) — that is, the observed sample mean. * + * @Deprecated 1.18.0 + * + * @see Statistical\Distributions\StandardNormal::zTest() + * Use the zTest() method in the Statistical\Distributions\StandardNormal class instead + * * @param float $dataSet * @param float $m0 Alpha Parameter * @param float $sigma Beta Parameter @@ -2106,15 +1982,6 @@ class Statistical */ public static function ZTEST($dataSet, $m0, $sigma = null) { - $dataSet = Functions::flattenArrayIndexed($dataSet); - $m0 = Functions::flattenSingleValue($m0); - $sigma = Functions::flattenSingleValue($sigma); - - if ($sigma === null) { - $sigma = StandardDeviations::STDEV($dataSet); - } - $n = count($dataSet); - - return 1 - self::NORMSDIST((Averages::average($dataSet) - $m0) / ($sigma / sqrt($n))); + return Statistical\Distributions\StandardNormal::zTest($dataSet, $m0, $sigma); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php index c9ef0f16..40adc9e3 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php @@ -4,7 +4,6 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\Statistical; class Confidence { @@ -39,6 +38,6 @@ class Confidence return Functions::NAN(); } - return Statistical::NORMSINV(1 - $alpha / 2) * $stdDev / sqrt($size); + return Distributions\StandardNormal::inverse(1 - $alpha / 2) * $stdDev / sqrt($size); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php new file mode 100644 index 00000000..87b464fa --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php @@ -0,0 +1,121 @@ +getMessage(); + } + + if (($value <= 0) || ($stdDev <= 0)) { + return Functions::NAN(); + } + + return StandardNormal::cumulative((log($value) - $mean) / $stdDev); + } + + /** + * LOGNORM.DIST. + * + * Returns the lognormal distribution of x, where ln(x) is normally distributed + * with parameters mean and standard_dev. + * + * @param mixed (float) $value + * @param mixed (float) $mean + * @param mixed (float) $stdDev + * @param mixed (bool) $cumulative + * + * @return float|string The result, or a string containing an error + */ + public static function distribution($value, $mean, $stdDev, $cumulative = false) + { + $value = Functions::flattenSingleValue($value); + $mean = Functions::flattenSingleValue($mean); + $stdDev = Functions::flattenSingleValue($stdDev); + $cumulative = Functions::flattenSingleValue($cumulative); + + try { + $value = self::validateFloat($value); + $mean = self::validateFloat($mean); + $stdDev = self::validateFloat($stdDev); + $cumulative = self::validateBool($cumulative); + } catch (Exception $e) { + return $e->getMessage(); + } + + if (($value <= 0) || ($stdDev <= 0)) { + return Functions::NAN(); + } + + if ($cumulative === true) { + return StandardNormal::distribution((log($value) - $mean) / $stdDev, true); + } + + return (1 / (sqrt(2 * M_PI) * $stdDev * $value)) * + exp(0 - ((log($value) - $mean) ** 2 / (2 * $stdDev ** 2))); + } + + /** + * LOGINV. + * + * Returns the inverse of the normal cumulative distribution + * + * @param mixed (float) $probability + * @param mixed (float) $mean + * @param mixed (float) $stdDev + * + * @return float|string The result, or a string containing an error + * + * @TODO Try implementing P J Acklam's refinement algorithm for greater + * accuracy if I can get my head round the mathematics + * (as described at) http://home.online.no/~pjacklam/notes/invnorm/ + */ + public static function inverse($probability, $mean, $stdDev) + { + $probability = Functions::flattenSingleValue($probability); + $mean = Functions::flattenSingleValue($mean); + $stdDev = Functions::flattenSingleValue($stdDev); + + try { + $probability = self::validateProbability($probability); + $mean = self::validateFloat($mean); + $stdDev = self::validateFloat($stdDev); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($stdDev <= 0) { + return Functions::NAN(); + } + + return exp($mean + $stdDev * StandardNormal::inverse($probability)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php new file mode 100644 index 00000000..b0c5552a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php @@ -0,0 +1,168 @@ +getMessage(); + } + + if ($stdDev < 0) { + return Functions::NAN(); + } + + if ($cumulative) { + return 0.5 * (1 + Engineering\Erf::erfValue(($value - $mean) / ($stdDev * sqrt(2)))); + } + + return (1 / (self::SQRT2PI * $stdDev)) * exp(0 - (($value - $mean) ** 2 / (2 * ($stdDev * $stdDev)))); + } + + /** + * NORMINV. + * + * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. + * + * @param mixed (float) $probability + * @param mixed (float) $mean Mean Value + * @param mixed (float) $stdDev Standard Deviation + * + * @return float|string The result, or a string containing an error + */ + public static function inverse($probability, $mean, $stdDev) + { + $probability = Functions::flattenSingleValue($probability); + $mean = Functions::flattenSingleValue($mean); + $stdDev = Functions::flattenSingleValue($stdDev); + + try { + $probability = self::validateProbability($probability); + $mean = self::validateFloat($mean); + $stdDev = self::validateFloat($stdDev); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($stdDev < 0) { + return Functions::NAN(); + } + + return (self::inverseNcdf($probability) * $stdDev) + $mean; + } + + /* + * inverse_ncdf.php + * ------------------- + * begin : Friday, January 16, 2004 + * copyright : (C) 2004 Michael Nickerson + * email : nickersonm@yahoo.com + * + */ + private static function inverseNcdf($p) + { + // Inverse ncdf approximation by Peter J. Acklam, implementation adapted to + // PHP by Michael Nickerson, using Dr. Thomas Ziegler's C implementation as + // a guide. http://home.online.no/~pjacklam/notes/invnorm/index.html + // I have not checked the accuracy of this implementation. Be aware that PHP + // will truncate the coeficcients to 14 digits. + + // You have permission to use and distribute this function freely for + // whatever purpose you want, but please show common courtesy and give credit + // where credit is due. + + // Input paramater is $p - probability - where 0 < p < 1. + + // Coefficients in rational approximations + static $a = [ + 1 => -3.969683028665376e+01, + 2 => 2.209460984245205e+02, + 3 => -2.759285104469687e+02, + 4 => 1.383577518672690e+02, + 5 => -3.066479806614716e+01, + 6 => 2.506628277459239e+00, + ]; + + static $b = [ + 1 => -5.447609879822406e+01, + 2 => 1.615858368580409e+02, + 3 => -1.556989798598866e+02, + 4 => 6.680131188771972e+01, + 5 => -1.328068155288572e+01, + ]; + + static $c = [ + 1 => -7.784894002430293e-03, + 2 => -3.223964580411365e-01, + 3 => -2.400758277161838e+00, + 4 => -2.549732539343734e+00, + 5 => 4.374664141464968e+00, + 6 => 2.938163982698783e+00, + ]; + + static $d = [ + 1 => 7.784695709041462e-03, + 2 => 3.224671290700398e-01, + 3 => 2.445134137142996e+00, + 4 => 3.754408661907416e+00, + ]; + + // Define lower and upper region break-points. + $p_low = 0.02425; //Use lower region approx. below this + $p_high = 1 - $p_low; //Use upper region approx. above this + + if (0 < $p && $p < $p_low) { + // Rational approximation for lower region. + $q = sqrt(-2 * log($p)); + + return ((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / + (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); + } elseif ($p_high < $p && $p < 1) { + // Rational approximation for upper region. + $q = sqrt(-2 * log(1 - $p)); + + return -((((($c[1] * $q + $c[2]) * $q + $c[3]) * $q + $c[4]) * $q + $c[5]) * $q + $c[6]) / + (((($d[1] * $q + $d[2]) * $q + $d[3]) * $q + $d[4]) * $q + 1); + } + + // Rational approximation for central region. + $q = $p - 0.5; + $r = $q * $q; + + return ((((($a[1] * $r + $a[2]) * $r + $a[3]) * $r + $a[4]) * $r + $a[5]) * $r + $a[6]) * $q / + ((((($b[1] * $r + $b[2]) * $r + $b[3]) * $r + $b[4]) * $r + $b[5]) * $r + 1); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php new file mode 100644 index 00000000..c3049f6d --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php @@ -0,0 +1,89 @@ + Date: Sun, 28 Mar 2021 20:35:40 +0900 Subject: [PATCH 152/187] Introduce PHPStan To improve the feedback loop on code quality with a process that can be run locally by the developers, instead of only on Scrutinizer. --- .github/workflows/main.yml | 31 +++++ composer.json | 4 +- composer.lock | 62 +++++++++- phpstan.neon.dist | 11 ++ .../Calculation/Calculation.php | 27 +++-- src/PhpSpreadsheet/Calculation/DateTime.php | 4 +- src/PhpSpreadsheet/Calculation/Financial.php | 2 + src/PhpSpreadsheet/Chart/Renderer/JpGraph.php | 4 + src/PhpSpreadsheet/IOFactory.php | 2 +- src/PhpSpreadsheet/Reader/Xls.php | 67 ++++++----- src/PhpSpreadsheet/Reader/Xls/Color.php | 2 +- src/PhpSpreadsheet/Reader/Xlsx.php | 10 +- src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 2 +- src/PhpSpreadsheet/Reader/Xml.php | 1 + src/PhpSpreadsheet/Shared/Drawing.php | 2 + src/PhpSpreadsheet/Shared/Font.php | 1 + .../Shared/JAMA/EigenvalueDecomposition.php | 15 ++- .../Shared/JAMA/LUDecomposition.php | 2 + .../JAMA/SingularValueDecomposition.php | 1 + src/PhpSpreadsheet/Shared/OLE.php | 5 +- src/PhpSpreadsheet/Shared/Trend/Trend.php | 2 + src/PhpSpreadsheet/Spreadsheet.php | 7 +- src/PhpSpreadsheet/Style/Border.php | 5 +- src/PhpSpreadsheet/Style/Borders.php | 15 +-- .../Style/NumberFormat/NumberFormatter.php | 1 + src/PhpSpreadsheet/Style/Style.php | 106 +++++++++--------- src/PhpSpreadsheet/Worksheet/AutoFilter.php | 3 + src/PhpSpreadsheet/Writer/Xls.php | 1 + src/PhpSpreadsheet/Writer/Xls/Parser.php | 6 +- src/PhpSpreadsheet/Writer/Xls/Worksheet.php | 79 +++++-------- src/PhpSpreadsheet/Writer/Xls/Xf.php | 87 ++++++++------ src/PhpSpreadsheet/Writer/Xlsx/Chart.php | 5 +- .../Functions/DateTime/WeekDayTest.php | 8 +- .../Reader/Security/XmlScannerTest.php | 2 +- 34 files changed, 370 insertions(+), 212 deletions(-) create mode 100644 phpstan.neon.dist diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ce38f646..87d933e2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -124,6 +124,37 @@ jobs: - name: Code style with PHP_CodeSniffer run: ./vendor/bin/phpcs -q --report=checkstyle | cs2pr + phpstan: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 7.4 + extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib + coverage: none + tools: cs2pr + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --prefer-dist --optimize-autoloader + + - name: Static analysis with PHPStan + run: ./vendor/bin/phpstan analyse + coverage: runs-on: ubuntu-latest steps: diff --git a/composer.json b/composer.json index 3b4ed556..d0c3a16d 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,8 @@ "check": [ "php-cs-fixer fix --ansi --dry-run --diff", "phpcs", - "phpunit --color=always" + "phpunit --color=always", + "phpstan analyse --ansi" ], "fix": [ "php-cs-fixer fix --ansi" @@ -79,6 +80,7 @@ "jpgraph/jpgraph": "^4.0", "mpdf/mpdf": "^8.0", "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^0.12.82", "phpunit/phpunit": "^8.5", "squizlabs/php_codesniffer": "^3.5", "tecnickcom/tcpdf": "^6.3" diff --git a/composer.lock b/composer.lock index 3f6efb00..e4060972 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6c8f34baf3385a533fade30a9a9ad6f1", + "content-hash": "89b62d75519340c289a3a763245f1ca0", "packages": [ { "name": "ezyang/htmlpurifier", @@ -1963,6 +1963,66 @@ }, "time": "2021-03-17T13:42:18+00:00" }, + { + "name": "phpstan/phpstan", + "version": "0.12.82", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3920f0fb0aff39263d3a4cb0bca120a67a1a6a11", + "reference": "3920f0fb0aff39263d3a4cb0bca120a67a1a6a11", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.12-dev" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "source": "https://github.com/phpstan/phpstan/tree/0.12.82" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpstan", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", + "type": "tidelift" + } + ], + "time": "2021-03-19T06:08:17+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "7.0.14", diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 00000000..476513dc --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,11 @@ +parameters: + level: 1 + paths: + - src/ + - tests/ + ignoreErrors: + - '~^Class GdImage not found\.$~' + + # Ignore all JpGraph issues + - '~^Constant (MARK_CIRCLE|MARK_CROSS|MARK_DIAMOND|MARK_DTRIANGLE|MARK_FILLEDCIRCLE|MARK_SQUARE|MARK_STAR|MARK_UTRIANGLE|MARK_X|SIDE_RIGHT) not found\.$~' + - '~^Instantiated class (AccBarPlot|AccLinePlot|BarPlot|ContourPlot|Graph|GroupBarPlot|GroupBarPlot|LinePlot|LinePlot|PieGraph|PiePlot|PiePlot3D|PiePlotC|RadarGraph|RadarPlot|ScatterPlot|Spline|StockPlot) not found\.$~' diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 967d05e5..0aa2a6da 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -3154,6 +3154,7 @@ class Calculation // Return Excel errors "as is" return $value; } + // Return strings wrapped in quotes return self::FORMULA_STRING_QUOTE . $value . self::FORMULA_STRING_QUOTE; } elseif ((is_float($value)) && ((is_nan($value)) || (is_infinite($value)))) { @@ -3794,13 +3795,13 @@ class Calculation $pCellParent = ($pCell !== null) ? $pCell->getWorksheet() : null; $regexpMatchString = '/^(' . self::CALCULATION_REGEXP_FUNCTION . - '|' . self::CALCULATION_REGEXP_CELLREF . - '|' . self::CALCULATION_REGEXP_NUMBER . - '|' . self::CALCULATION_REGEXP_STRING . - '|' . self::CALCULATION_REGEXP_OPENBRACE . - '|' . self::CALCULATION_REGEXP_DEFINEDNAME . - '|' . self::CALCULATION_REGEXP_ERROR . - ')/sui'; + '|' . self::CALCULATION_REGEXP_CELLREF . + '|' . self::CALCULATION_REGEXP_NUMBER . + '|' . self::CALCULATION_REGEXP_STRING . + '|' . self::CALCULATION_REGEXP_OPENBRACE . + '|' . self::CALCULATION_REGEXP_DEFINEDNAME . + '|' . self::CALCULATION_REGEXP_ERROR . + ')/sui'; // Start with initialisation $index = 0; @@ -3939,6 +3940,7 @@ class Calculation } // Check the argument count $argumentCountError = false; + $expectedArgumentCountString = null; if (is_numeric($expectedArgumentCount)) { if ($expectedArgumentCount < 0) { if ($argumentCount > abs($expectedArgumentCount)) { @@ -4203,7 +4205,7 @@ class Calculation ((preg_match('/^' . self::CALCULATION_REGEXP_CELLREF . '.*/Ui', substr($formula, $index), $match)) && ($output[count($output) - 1]['type'] == 'Cell Reference') || (preg_match('/^' . self::CALCULATION_REGEXP_DEFINEDNAME . '.*/miu', substr($formula, $index), $match)) && - ($output[count($output) - 1]['type'] == 'Defined Name' || $output[count($output) - 1]['type'] == 'Value') + ($output[count($output) - 1]['type'] == 'Defined Name' || $output[count($output) - 1]['type'] == 'Value') ) ) { while ( @@ -4645,6 +4647,9 @@ class Calculation $this->debugLog->writeDebugLog('Evaluating Function ', self::localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's')); } if ((isset(self::$phpSpreadsheetFunctions[$functionName])) || (isset(self::$controlFunctions[$functionName]))) { // function + $passByReference = false; + $passCellReference = false; + $functionCall = null; if (isset(self::$phpSpreadsheetFunctions[$functionName])) { $functionCall = self::$phpSpreadsheetFunctions[$functionName]['functionCall']; $passByReference = isset(self::$phpSpreadsheetFunctions[$functionName]['passByReference']); @@ -4945,6 +4950,9 @@ class Calculation } break; + + default: + throw new Exception('Unsupported binary comparison operation'); } // Log the result details @@ -5062,6 +5070,9 @@ class Calculation $result = $operand1 ** $operand2; break; + + default: + throw new Exception('Unsupported numeric binary operation'); } } } diff --git a/src/PhpSpreadsheet/Calculation/DateTime.php b/src/PhpSpreadsheet/Calculation/DateTime.php index 744d9589..e3580cde 100644 --- a/src/PhpSpreadsheet/Calculation/DateTime.php +++ b/src/PhpSpreadsheet/Calculation/DateTime.php @@ -651,7 +651,7 @@ class DateTime * * Returns the ISO 8601 week number of the year for a specified date. * - * @Deprecated 2.0.0 Use the funcIsoWeeknum method in the DateTimeExcel\Isoweeknum class instead + * @Deprecated 2.0.0 Use the funcIsoWeeknum method in the DateTimeExcel\IsoWeekNum class instead * * Excel Function: * ISOWEEKNUM(dateValue) @@ -663,7 +663,7 @@ class DateTime */ public static function ISOWEEKNUM($dateValue = 1) { - return DateTimeExcel\IsoweekNum::funcIsoWeekNum($dateValue); + return DateTimeExcel\IsoWeekNum::funcIsoWeekNum($dateValue); } /** diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 11bbf7a6..547ad6b3 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -20,6 +20,8 @@ class Financial { $pmt = self::PMT($rate, $nper, $pv, $fv, $type); $capital = $pv; + $interest = 0; + $principal = 0; for ($i = 1; $i <= $per; ++$i) { $interest = ($type && $i == 1) ? 0 : -$capital * $rate; $principal = $pmt - $interest; diff --git a/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php b/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php index 02fbfed7..0ab70870 100644 --- a/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php +++ b/src/PhpSpreadsheet/Chart/Renderer/JpGraph.php @@ -301,6 +301,8 @@ class JpGraph implements IRenderer $seriesPlots = []; if ($grouping == 'percentStacked') { $sumValues = $this->percentageSumCalculation($groupID, $seriesCount); + } else { + $sumValues = []; } // Loop through each data series in turn @@ -376,6 +378,8 @@ class JpGraph implements IRenderer $seriesPlots = []; if ($grouping == 'percentStacked') { $sumValues = $this->percentageSumCalculation($groupID, $seriesCount); + } else { + $sumValues = []; } // Loop through each data series in turn diff --git a/src/PhpSpreadsheet/IOFactory.php b/src/PhpSpreadsheet/IOFactory.php index ab04e969..06006edc 100644 --- a/src/PhpSpreadsheet/IOFactory.php +++ b/src/PhpSpreadsheet/IOFactory.php @@ -120,7 +120,7 @@ abstract class IOFactory $reader = self::createReader($guessedReader); // Let's see if we are lucky - if (isset($reader) && $reader->canRead($filename)) { + if ($reader->canRead($filename)) { return $reader; } } diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 6d6b87fd..faa047da 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -801,9 +801,10 @@ class Xls extends BaseReader } // treat MSODRAWINGGROUP records, workbook-level Escher + $escherWorkbook = null; if (!$this->readDataOnly && $this->drawingGroupData) { - $escherWorkbook = new Escher(); - $reader = new Xls\Escher($escherWorkbook); + $escher = new Escher(); + $reader = new Xls\Escher($escher); $escherWorkbook = $reader->load($this->drawingGroupData); } @@ -1133,38 +1134,40 @@ class Xls extends BaseReader continue 2; } - $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection(); - $BSE = $BSECollection[$BSEindex - 1]; - $blipType = $BSE->getBlipType(); + if ($escherWorkbook) { + $BSECollection = $escherWorkbook->getDggContainer()->getBstoreContainer()->getBSECollection(); + $BSE = $BSECollection[$BSEindex - 1]; + $blipType = $BSE->getBlipType(); - // need check because some blip types are not supported by Escher reader such as EMF - if ($blip = $BSE->getBlip()) { - $ih = imagecreatefromstring($blip->getData()); - $drawing = new MemoryDrawing(); - $drawing->setImageResource($ih); + // need check because some blip types are not supported by Escher reader such as EMF + if ($blip = $BSE->getBlip()) { + $ih = imagecreatefromstring($blip->getData()); + $drawing = new MemoryDrawing(); + $drawing->setImageResource($ih); - // width, height, offsetX, offsetY - $drawing->setResizeProportional(false); - $drawing->setWidth($width); - $drawing->setHeight($height); - $drawing->setOffsetX($offsetX); - $drawing->setOffsetY($offsetY); + // width, height, offsetX, offsetY + $drawing->setResizeProportional(false); + $drawing->setWidth($width); + $drawing->setHeight($height); + $drawing->setOffsetX($offsetX); + $drawing->setOffsetY($offsetY); - switch ($blipType) { - case BSE::BLIPTYPE_JPEG: - $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG); - $drawing->setMimeType(MemoryDrawing::MIMETYPE_JPEG); + switch ($blipType) { + case BSE::BLIPTYPE_JPEG: + $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG); + $drawing->setMimeType(MemoryDrawing::MIMETYPE_JPEG); - break; - case BSE::BLIPTYPE_PNG: - $drawing->setRenderingFunction(MemoryDrawing::RENDERING_PNG); - $drawing->setMimeType(MemoryDrawing::MIMETYPE_PNG); + break; + case BSE::BLIPTYPE_PNG: + $drawing->setRenderingFunction(MemoryDrawing::RENDERING_PNG); + $drawing->setMimeType(MemoryDrawing::MIMETYPE_PNG); - break; + break; + } + + $drawing->setWorksheet($this->phpSheet); + $drawing->setCoordinates($spContainer->getStartCoordinates()); } - - $drawing->setWorksheet($this->phpSheet); - $drawing->setCoordinates($spContainer->getStartCoordinates()); } break; @@ -2742,6 +2745,7 @@ class Xls extends BaseReader $sheetType = ord($recordData[5]); // offset: 6; size: var; sheet name + $rec_name = null; if ($this->version == self::XLS_BIFF8) { $string = self::readUnicodeStringShort(substr($recordData, 6)); $rec_name = $string['value']; @@ -3018,12 +3022,14 @@ class Xls extends BaseReader // bit: 3; mask: 0x03; 0 = ordinary; 1 = Rich-Text $hasRichText = (($optionFlags & 0x08) != 0); + $formattingRuns = 0; if ($hasRichText) { // number of Rich-Text formatting runs $formattingRuns = self::getUInt2d($recordData, $pos); $pos += 2; } + $extendedRunLength = 0; if ($hasAsian) { // size of Asian phonetic setting $extendedRunLength = self::getInt4d($recordData, $pos); @@ -3034,6 +3040,7 @@ class Xls extends BaseReader $len = ($isCompressed) ? $numChars : $numChars * 2; // look up limit position - Check it again to be sure that no error occurs when parsing SST structure + $limitpos = null; foreach ($spliceOffsets as $spliceOffset) { // it can happen that the string is empty, therefore we need // <= and not just < @@ -4385,6 +4392,8 @@ class Xls extends BaseReader // offset: 4; size: 2; index to first visible colum $firstVisibleColumn = self::getUInt2d($recordData, 4); + $zoomscaleInPageBreakPreview = 0; + $zoomscaleInNormalView = 0; if ($this->version === self::XLS_BIFF8) { // offset: 8; size: 2; not used // offset: 10; size: 2; cached magnification factor in page break preview (in percent); 0 = Default (60%) @@ -7636,6 +7645,8 @@ class Xls extends BaseReader $size = 9; break; + default: + throw new PhpSpreadsheetException('Unsupported BIFF8 constant'); } return [ diff --git a/src/PhpSpreadsheet/Reader/Xls/Color.php b/src/PhpSpreadsheet/Reader/Xls/Color.php index c45f88c7..06c2d0b9 100644 --- a/src/PhpSpreadsheet/Reader/Xls/Color.php +++ b/src/PhpSpreadsheet/Reader/Xls/Color.php @@ -20,7 +20,7 @@ class Color if ($color <= 0x07 || $color >= 0x40) { // special built-in color return Color\BuiltIn::lookup($color); - } elseif (isset($palette, $palette[$color - 8])) { + } elseif (isset($palette[$color - 8])) { // palette color, color index 0x08 maps to pallete index 0 return $palette[$color - 8]; } diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 219a49fb..e47ad7b0 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -430,7 +430,7 @@ class Xlsx extends BaseReader 'SimpleXMLElement', Settings::getLibXmlLoaderOptions() ); - if (isset($xmlStrings, $xmlStrings->si)) { + if (isset($xmlStrings->si)) { foreach ($xmlStrings->si as $val) { if (isset($val->t)) { $sharedStrings[] = StringHelper::controlCharacterOOXML2PHP((string) $val->t); @@ -511,10 +511,7 @@ class Xlsx extends BaseReader $numFmt = NumberFormat::builtInFormatCode((int) $xf['numFmtId']); } } - $quotePrefix = false; - if (isset($xf['quotePrefix'])) { - $quotePrefix = (bool) $xf['quotePrefix']; - } + $quotePrefix = (bool) ($xf['quotePrefix'] ?? false); $style = (object) [ 'numFmt' => $numFmt ?? NumberFormat::FORMAT_GENERAL, @@ -544,6 +541,8 @@ class Xlsx extends BaseReader } } + $quotePrefix = (bool) ($xf['quotePrefix'] ?? false); + $cellStyle = (object) [ 'numFmt' => $numFmt, 'font' => $xmlStyles->fonts->font[(int) ($xf['fontId'])], @@ -1081,6 +1080,7 @@ class Xlsx extends BaseReader } if ($xmlSheet->drawing && !$this->readDataOnly) { $unparsedDrawings = []; + $fileDrawing = null; foreach ($xmlSheet->drawing as $drawing) { $drawingRelId = (string) self::getArrayItem($drawing->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), 'id'); $fileDrawing = $drawings[$drawingRelId]; diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index 5a3439f2..5e86c60a 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -61,7 +61,7 @@ class Chart $XaxisLabel = $YaxisLabel = $legend = $title = null; $dispBlanksAs = $plotVisOnly = null; - + $plotArea = null; foreach ($chartElementsC as $chartElementKey => $chartElement) { switch ($chartElementKey) { case 'chart': diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index a827d17a..58d38b0d 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -436,6 +436,7 @@ class Xml extends BaseReader // Create new Worksheet $spreadsheet->createSheet(); $spreadsheet->setActiveSheetIndex($worksheetID); + $worksheetName = ''; if (isset($worksheet_ss['Name'])) { $worksheetName = (string) $worksheet_ss['Name']; // Use false for $updateFormulaCellReferences to prevent adjustment of worksheet references in diff --git a/src/PhpSpreadsheet/Shared/Drawing.php b/src/PhpSpreadsheet/Shared/Drawing.php index f41fb695..67c015c4 100644 --- a/src/PhpSpreadsheet/Shared/Drawing.php +++ b/src/PhpSpreadsheet/Shared/Drawing.php @@ -171,6 +171,8 @@ class Drawing // Process the header // Structure: http://www.fastgraph.com/help/bmp_header_format.html + $width = 0; + $height = 0; if (substr($header, 0, 4) == '424d') { // Cut it in parts of 2 bytes $header_parts = str_split($header, 2); diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index 162e9730..4061b370 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -244,6 +244,7 @@ class Font // Try to get the exact text width in pixels $approximate = self::$autoSizeMethod == self::AUTOSIZE_METHOD_APPROX; + $columnWidth = 0; if (!$approximate) { $columnWidthAdjust = ceil(self::getTextWidthPixelsExact('n', $font, 0) * 1.07); diff --git a/src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php index 4c67c3a9..5c6ccfd3 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpSpreadsheet\Shared\JAMA; * conditioned, or even singular, so the validity of the equation * A = V*D*inverse(V) depends upon V.cond(). * - * @author Paul Meagher + * @author Paul Meagher * - * @version 1.1 + * @version 1.1 */ class EigenvalueDecomposition { @@ -70,6 +70,11 @@ class EigenvalueDecomposition private $cdivi; + /** + * @var array + */ + private $A; + /** * Symmetric Householder reduction to tridiagonal form. */ @@ -80,6 +85,7 @@ class EigenvalueDecomposition // Auto. Comp., Vol.ii-Linear Algebra, and the corresponding // Fortran subroutine in EISPACK. $this->d = $this->V[$this->n - 1]; + $j = 0; // Householder reduction to tridiagonal form. for ($i = $this->n - 1; $i > 0; --$i) { $i_ = $i - 1; @@ -781,9 +787,9 @@ class EigenvalueDecomposition /** * Constructor: Check for symmetry, then construct the eigenvalue decomposition. * - * @param mixed $Arg A Square matrix + * @param Matrix $Arg A Square matrix */ - public function __construct($Arg) + public function __construct(Matrix $Arg) { $this->A = $Arg->getArray(); $this->n = $Arg->getColumnDimension(); @@ -848,6 +854,7 @@ class EigenvalueDecomposition */ public function getD() { + $D = []; for ($i = 0; $i < $this->n; ++$i) { $D[$i] = array_fill(0, $this->n, 0.0); $D[$i][$i] = $this->d[$i]; diff --git a/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php index 6db17c28..e16d6a21 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php @@ -135,6 +135,7 @@ class LUDecomposition */ public function getL() { + $L = []; for ($i = 0; $i < $this->m; ++$i) { for ($j = 0; $j < $this->n; ++$j) { if ($i > $j) { @@ -159,6 +160,7 @@ class LUDecomposition */ public function getU() { + $U = []; for ($i = 0; $i < $this->n; ++$i) { for ($j = 0; $j < $this->n; ++$j) { if ($i <= $j) { diff --git a/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php index b997fb7c..afd9ed0f 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php @@ -476,6 +476,7 @@ class SingularValueDecomposition */ public function getS() { + $S = []; for ($i = 0; $i < $this->n; ++$i) { for ($j = 0; $j < $this->n; ++$j) { $S[$i][$j] = 0.0; diff --git a/src/PhpSpreadsheet/Shared/OLE.php b/src/PhpSpreadsheet/Shared/OLE.php index 1c745bdb..f65fbca7 100644 --- a/src/PhpSpreadsheet/Shared/OLE.php +++ b/src/PhpSpreadsheet/Shared/OLE.php @@ -21,6 +21,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared; // +----------------------------------------------------------------------+ // +use PhpOffice\PhpSpreadsheet\Exception; use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException; use PhpOffice\PhpSpreadsheet\Shared\OLE\ChainedBlockStream; use PhpOffice\PhpSpreadsheet\Shared\OLE\PPS\Root; @@ -317,7 +318,7 @@ class OLE break; default: - break; + throw new Exception('Unsupported PPS type'); } fseek($fh, 1, SEEK_CUR); $pps->Type = $type; @@ -496,7 +497,7 @@ class OLE */ public static function localDateToOLE($date) { - if (!isset($date)) { + if (!$date) { return "\x00\x00\x00\x00\x00\x00\x00\x00"; } diff --git a/src/PhpSpreadsheet/Shared/Trend/Trend.php b/src/PhpSpreadsheet/Shared/Trend/Trend.php index d0a117cb..24570d59 100644 --- a/src/PhpSpreadsheet/Shared/Trend/Trend.php +++ b/src/PhpSpreadsheet/Shared/Trend/Trend.php @@ -91,6 +91,8 @@ class Trend case self::TREND_BEST_FIT_NO_POLY: // If the request is to determine the best fit regression, then we test each Trend line in turn // Start by generating an instance of each available Trend method + $bestFit = []; + $bestFitValue = []; foreach (self::$trendTypes as $trendMethod) { $className = '\PhpOffice\PhpSpreadsheet\Shared\Trend\\' . $trendType . 'BestFit'; $bestFit[$trendMethod] = new $className($yValues, $xValues, $const); diff --git a/src/PhpSpreadsheet/Spreadsheet.php b/src/PhpSpreadsheet/Spreadsheet.php index 51f558a1..59304804 100644 --- a/src/PhpSpreadsheet/Spreadsheet.php +++ b/src/PhpSpreadsheet/Spreadsheet.php @@ -55,7 +55,7 @@ class Spreadsheet /** * Calculation Engine. * - * @var Calculation + * @var null|Calculation */ private $calculationEngine; @@ -505,8 +505,8 @@ class Spreadsheet */ public function __destruct() { - $this->calculationEngine = null; $this->disconnectWorksheets(); + $this->calculationEngine = null; } /** @@ -527,7 +527,7 @@ class Spreadsheet /** * Return the calculation engine for this worksheet. * - * @return Calculation + * @return null|Calculation */ public function getCalculationEngine() { @@ -1343,6 +1343,7 @@ class Spreadsheet // remove cellXfs without references and create mapping so we can update xfIndex // for all cells and columns $countNeededCellXfs = 0; + $map = []; foreach ($this->cellXfCollection as $index => $cellXf) { if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf ++$countNeededCellXfs; diff --git a/src/PhpSpreadsheet/Style/Border.php b/src/PhpSpreadsheet/Style/Border.php index 1d3096f0..d11fa0ca 100644 --- a/src/PhpSpreadsheet/Style/Border.php +++ b/src/PhpSpreadsheet/Style/Border.php @@ -47,11 +47,8 @@ class Border extends Supervisor * @param bool $isSupervisor Flag indicating if this is a supervisor or not * Leave this value at default unless you understand exactly what * its ramifications are - * @param bool $isConditional Flag indicating if this is a conditional style or not - * Leave this value at default unless you understand exactly what - * its ramifications are */ - public function __construct($isSupervisor = false, $isConditional = false) + public function __construct($isSupervisor = false) { // Supervisor? parent::__construct($isSupervisor); diff --git a/src/PhpSpreadsheet/Style/Borders.php b/src/PhpSpreadsheet/Style/Borders.php index a1acfdd4..eeb4932a 100644 --- a/src/PhpSpreadsheet/Style/Borders.php +++ b/src/PhpSpreadsheet/Style/Borders.php @@ -95,21 +95,18 @@ class Borders extends Supervisor * @param bool $isSupervisor Flag indicating if this is a supervisor or not * Leave this value at default unless you understand exactly what * its ramifications are - * @param bool $isConditional Flag indicating if this is a conditional style or not - * Leave this value at default unless you understand exactly what - * its ramifications are */ - public function __construct($isSupervisor = false, $isConditional = false) + public function __construct($isSupervisor = false) { // Supervisor? parent::__construct($isSupervisor); // Initialise values - $this->left = new Border($isSupervisor, $isConditional); - $this->right = new Border($isSupervisor, $isConditional); - $this->top = new Border($isSupervisor, $isConditional); - $this->bottom = new Border($isSupervisor, $isConditional); - $this->diagonal = new Border($isSupervisor, $isConditional); + $this->left = new Border($isSupervisor); + $this->right = new Border($isSupervisor); + $this->top = new Border($isSupervisor); + $this->bottom = new Border($isSupervisor); + $this->diagonal = new Border($isSupervisor); $this->diagonalDirection = self::DIAGONAL_NONE; // Specially for supervisor diff --git a/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php index 36cdcf03..9a4f32ac 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php @@ -35,6 +35,7 @@ class NumberFormatter if ($maskingBlockCount > 1) { $maskingBlocks = array_reverse($maskingBlocks[0]); + $offset = 0; foreach ($maskingBlocks as $block) { $size = strlen($block[0]); $divisor = 10 ** $size; diff --git a/src/PhpSpreadsheet/Style/Style.php b/src/PhpSpreadsheet/Style/Style.php index 7fec9a00..d3653ed5 100644 --- a/src/PhpSpreadsheet/Style/Style.php +++ b/src/PhpSpreadsheet/Style/Style.php @@ -80,7 +80,7 @@ class Style extends Supervisor // Initialise values $this->font = new Font($isSupervisor, $isConditional); $this->fill = new Fill($isSupervisor, $isConditional); - $this->borders = new Borders($isSupervisor, $isConditional); + $this->borders = new Borders($isSupervisor); $this->alignment = new Alignment($isSupervisor, $isConditional); $this->numberFormat = new NumberFormat($isSupervisor, $isConditional); $this->protection = new Protection($isSupervisor, $isConditional); @@ -257,11 +257,11 @@ class Style extends Supervisor // start column index for region $colStart = ($x == 3) ? Coordinate::stringFromColumnIndex($rangeEnd[0]) - : Coordinate::stringFromColumnIndex($rangeStart[0] + $x - 1); + : Coordinate::stringFromColumnIndex($rangeStart[0] + $x - 1); // end column index for region $colEnd = ($x == 1) ? Coordinate::stringFromColumnIndex($rangeStart[0]) - : Coordinate::stringFromColumnIndex($rangeEnd[0] - $xMax + $x); + : Coordinate::stringFromColumnIndex($rangeEnd[0] - $xMax + $x); for ($y = 1; $y <= $yMax; ++$y) { // which edges are touching the region @@ -349,56 +349,11 @@ class Style extends Supervisor } // First loop through columns, rows, or cells to find out which styles are affected by this operation - switch ($selectionType) { - case 'COLUMN': - $oldXfIndexes = []; - for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { - $oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true; - } - foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) { - $cellIterator = $columnIterator->getCellIterator(); - $cellIterator->setIterateOnlyExistingCells(true); - foreach ($cellIterator as $columnCell) { - if ($columnCell !== null) { - $columnCell->getStyle()->applyFromArray($pStyles); - } - } - } - - break; - case 'ROW': - $oldXfIndexes = []; - for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { - if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() === null) { - $oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style - } else { - $oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true; - } - } - foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) { - $cellIterator = $rowIterator->getCellIterator(); - $cellIterator->setIterateOnlyExistingCells(true); - foreach ($cellIterator as $rowCell) { - if ($rowCell !== null) { - $rowCell->getStyle()->applyFromArray($pStyles); - } - } - } - - break; - case 'CELL': - $oldXfIndexes = []; - for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { - for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { - $oldXfIndexes[$this->getActiveSheet()->getCellByColumnAndRow($col, $row)->getXfIndex()] = true; - } - } - - break; - } + $oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStart, $rangeEnd, $rangeStart0, $rangeEnd0, $pStyles); // clone each of the affected styles, apply the style array, and add the new styles to the workbook $workbook = $this->getActiveSheet()->getParent(); + $newXfIndexes = []; foreach ($oldXfIndexes as $oldXfIndex => $dummy) { $style = $workbook->getCellXfByIndex($oldXfIndex); $newStyle = clone $style; @@ -472,6 +427,57 @@ class Style extends Supervisor return $this; } + private function getOldXfIndexes(string $selectionType, array $rangeStart, array $rangeEnd, string $rangeStart0, string $rangeEnd0, array $pStyles): array + { + $oldXfIndexes = []; + switch ($selectionType) { + case 'COLUMN': + for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { + $oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true; + } + foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) { + $cellIterator = $columnIterator->getCellIterator(); + $cellIterator->setIterateOnlyExistingCells(true); + foreach ($cellIterator as $columnCell) { + if ($columnCell !== null) { + $columnCell->getStyle()->applyFromArray($pStyles); + } + } + } + + break; + case 'ROW': + for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { + if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() === null) { + $oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style + } else { + $oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true; + } + } + foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) { + $cellIterator = $rowIterator->getCellIterator(); + $cellIterator->setIterateOnlyExistingCells(true); + foreach ($cellIterator as $rowCell) { + if ($rowCell !== null) { + $rowCell->getStyle()->applyFromArray($pStyles); + } + } + } + + break; + case 'CELL': + for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { + for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { + $oldXfIndexes[$this->getActiveSheet()->getCellByColumnAndRow($col, $row)->getXfIndex()] = true; + } + } + + break; + } + + return $oldXfIndexes; + } + /** * Get Fill. * diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/src/PhpSpreadsheet/Worksheet/AutoFilter.php index 22fc775c..dc876ee9 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -779,6 +779,9 @@ class AutoFilter case AutoFilter\Column::AUTOFILTER_FILTERTYPE_TOPTENFILTER: $ruleValues = []; $dataRowCount = $rangeEnd[1] - $rangeStart[1]; + $toptenRuleType = null; + $ruleValue = null; + $ruleOperator = null; foreach ($rules as $rule) { // We should only ever have one Dynamic Filter Rule anyway $toptenRuleType = $rule->getGrouping(); diff --git a/src/PhpSpreadsheet/Writer/Xls.php b/src/PhpSpreadsheet/Writer/Xls.php index c7c2e7d6..d458fc74 100644 --- a/src/PhpSpreadsheet/Writer/Xls.php +++ b/src/PhpSpreadsheet/Writer/Xls.php @@ -420,6 +420,7 @@ class Xls extends BaseWriter private function processDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing): void { + $blipType = null; $blipData = ''; $filename = $drawing->getPath(); diff --git a/src/PhpSpreadsheet/Writer/Xls/Parser.php b/src/PhpSpreadsheet/Writer/Xls/Parser.php index f89957a4..98b2b5cc 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Parser.php +++ b/src/PhpSpreadsheet/Writer/Xls/Parser.php @@ -747,7 +747,7 @@ class Parser return pack('C', 0xFF); } - private function convertDefinedName(string $name): void + private function convertDefinedName(string $name): string { if (strlen($name) > 255) { throw new WriterException('Defined Name is too long'); @@ -764,7 +764,8 @@ class Parser $ptgRef = pack('Cvxx', $this->ptg['ptgName'], $nameReference); throw new WriterException('Cannot yet write formulae with defined names to Xls'); -// return $ptgRef; + + return $ptgRef; } /** @@ -968,6 +969,7 @@ class Parser */ private function advance() { + $token = ''; $i = $this->currentCharacter; $formula_length = strlen($this->formula); // eat up white spaces diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php index d2784d6d..8f6015de 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php @@ -1344,32 +1344,13 @@ class Worksheet extends BIFFwriter */ private function writeColinfo($col_array): void { - if (isset($col_array[0])) { - $colFirst = $col_array[0]; - } - if (isset($col_array[1])) { - $colLast = $col_array[1]; - } - if (isset($col_array[2])) { - $coldx = $col_array[2]; - } else { - $coldx = 8.43; - } - if (isset($col_array[3])) { - $xfIndex = $col_array[3]; - } else { - $xfIndex = 15; - } - if (isset($col_array[4])) { - $grbit = $col_array[4]; - } else { - $grbit = 0; - } - if (isset($col_array[5])) { - $level = $col_array[5]; - } else { - $level = 0; - } + $colFirst = $col_array[0] ?? null; + $colLast = $col_array[1] ?? null; + $coldx = $col_array[2] ?? 8.43; + $xfIndex = $col_array[3] ?? 15; + $grbit = $col_array[4] ?? 0; + $level = $col_array[5] ?? 0; + $record = 0x007D; // Record identifier $length = 0x000C; // Number of bytes to follow @@ -1425,13 +1406,6 @@ class Worksheet extends BIFFwriter $irefAct = 0; // Active cell ref $cref = 1; // Number of refs - if (!isset($rwLast)) { - $rwLast = $rwFirst; // Last row in reference - } - if (!isset($colLast)) { - $colLast = $colFirst; // Last col in reference - } - // Swap last row/col for first row/col as necessary if ($rwFirst > $rwLast) { [$rwFirst, $rwLast] = [$rwLast, $rwFirst]; @@ -1660,7 +1634,7 @@ class Worksheet extends BIFFwriter if (!isset($rwTop)) { $rwTop = $y; } - if (!isset($colLeft)) { + if (!$colLeft) { $colLeft = $x; } } else { @@ -1668,7 +1642,7 @@ class Worksheet extends BIFFwriter if (!isset($rwTop)) { $rwTop = 0; } - if (!isset($colLeft)) { + if (!$colLeft) { $colLeft = 0; } @@ -1684,7 +1658,7 @@ class Worksheet extends BIFFwriter // Determine which pane should be active. There is also the undocumented // option to override this should it be necessary: may be removed later. // - if (!isset($pnnAct)) { + if (!$pnnAct) { if ($x != 0 && $y != 0) { $pnnAct = 0; // Bottom right } @@ -2974,9 +2948,9 @@ class Worksheet extends BIFFwriter private function writeCFRule(Conditional $conditional): void { $record = 0x01B1; // Record identifier + $type = null; // Type of the CF + $operatorType = null; // Comparison operator - // $type : Type of the CF - // $operatorType : Comparison operator if ($conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) { $type = 0x02; $operatorType = 0x00; @@ -3141,6 +3115,11 @@ class Worksheet extends BIFFwriter // Text direction $flags |= (1 == 0 ? 0x80000000 : 0); + $dataBlockFont = null; + $dataBlockAlign = null; + $dataBlockBorder = null; + $dataBlockFill = null; + // Data Blocks if ($bFormatFont == 1) { // Font Name @@ -4398,15 +4377,6 @@ class Worksheet extends BIFFwriter $dataBlockFill = pack('v', $blockFillPatternStyle); $dataBlockFill .= pack('v', $colorIdxFg | ($colorIdxBg << 7)); } - if ($bFormatProt == 1) { - $dataBlockProtection = 0; - if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) { - $dataBlockProtection = 1; - } - if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) { - $dataBlockProtection = 1 << 1; - } - } $data = pack('CCvvVv', $type, $operatorType, $szValue1, $szValue2, $flags, 0x0000); if ($bFormatFont == 1) { // Block Formatting : OK @@ -4422,7 +4392,7 @@ class Worksheet extends BIFFwriter $data .= $dataBlockFill; } if ($bFormatProt == 1) { - $data .= $dataBlockProtection; + $data .= $this->getDataBlockProtection($conditional); } if ($operand1 !== null) { $data .= $operand1; @@ -4486,4 +4456,17 @@ class Worksheet extends BIFFwriter $data .= $cellRange; $this->append($header . $data); } + + private function getDataBlockProtection(Conditional $conditional): int + { + $dataBlockProtection = 0; + if ($conditional->getStyle()->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED) { + $dataBlockProtection = 1; + } + if ($conditional->getStyle()->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED) { + $dataBlockProtection = 1 << 1; + } + + return $dataBlockProtection; + } } diff --git a/src/PhpSpreadsheet/Writer/Xls/Xf.php b/src/PhpSpreadsheet/Writer/Xls/Xf.php index 90d21bcf..eca3d8e0 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Xf.php +++ b/src/PhpSpreadsheet/Writer/Xls/Xf.php @@ -115,6 +115,21 @@ class Xf */ private $rightBorderColor; + /** + * @var int + */ + private $diag; + + /** + * @var int + */ + private $diagColor; + + /** + * @var Style + */ + private $style; + /** * Constructor. * @@ -132,14 +147,14 @@ class Xf $this->foregroundColor = 0x40; $this->backgroundColor = 0x41; - $this->_diag = 0; + $this->diag = 0; $this->bottomBorderColor = 0x40; $this->topBorderColor = 0x40; $this->leftBorderColor = 0x40; $this->rightBorderColor = 0x40; - $this->_diag_color = 0x40; - $this->_style = $style; + $this->diagColor = 0x40; + $this->style = $style; } /** @@ -153,39 +168,39 @@ class Xf if ($this->isStyleXf) { $style = 0xFFF5; } else { - $style = self::mapLocked($this->_style->getProtection()->getLocked()); - $style |= self::mapHidden($this->_style->getProtection()->getHidden()) << 1; + $style = self::mapLocked($this->style->getProtection()->getLocked()); + $style |= self::mapHidden($this->style->getProtection()->getHidden()) << 1; } // Flags to indicate if attributes have been set. $atr_num = ($this->numberFormatIndex != 0) ? 1 : 0; $atr_fnt = ($this->fontIndex != 0) ? 1 : 0; - $atr_alc = ((int) $this->_style->getAlignment()->getWrapText()) ? 1 : 0; - $atr_bdr = (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) || - self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) || - self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) || - self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0; + $atr_alc = ((int) $this->style->getAlignment()->getWrapText()) ? 1 : 0; + $atr_bdr = (self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) || + self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) || + self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()) || + self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle())) ? 1 : 0; $atr_pat = ($this->foregroundColor != 0x40) ? 1 : 0; $atr_pat = ($this->backgroundColor != 0x41) ? 1 : $atr_pat; - $atr_pat = self::mapFillType($this->_style->getFill()->getFillType()) ? 1 : $atr_pat; - $atr_prot = self::mapLocked($this->_style->getProtection()->getLocked()) - | self::mapHidden($this->_style->getProtection()->getHidden()); + $atr_pat = self::mapFillType($this->style->getFill()->getFillType()) ? 1 : $atr_pat; + $atr_prot = self::mapLocked($this->style->getProtection()->getLocked()) + | self::mapHidden($this->style->getProtection()->getHidden()); // Zero the default border colour if the border has not been set. - if (self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) == 0) { + if (self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) == 0) { $this->bottomBorderColor = 0; } - if (self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) == 0) { + if (self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) == 0) { $this->topBorderColor = 0; } - if (self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle()) == 0) { + if (self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle()) == 0) { $this->rightBorderColor = 0; } - if (self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()) == 0) { + if (self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()) == 0) { $this->leftBorderColor = 0; } - if (self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) == 0) { - $this->_diag_color = 0; + if (self::mapBorderStyle($this->style->getBorders()->getDiagonal()->getBorderStyle()) == 0) { + $this->diagColor = 0; } $record = 0x00E0; // Record identifier @@ -194,9 +209,9 @@ class Xf $ifnt = $this->fontIndex; // Index to FONT record $ifmt = $this->numberFormatIndex; // Index to FORMAT record - $align = $this->mapHAlign($this->_style->getAlignment()->getHorizontal()); // Alignment - $align |= (int) $this->_style->getAlignment()->getWrapText() << 3; - $align |= self::mapVAlign($this->_style->getAlignment()->getVertical()) << 4; + $align = $this->mapHAlign($this->style->getAlignment()->getHorizontal()); // Alignment + $align |= (int) $this->style->getAlignment()->getWrapText() << 3; + $align |= self::mapVAlign($this->style->getAlignment()->getVertical()) << 4; $align |= $this->textJustLast << 7; $used_attrib = $atr_num << 2; @@ -209,35 +224,35 @@ class Xf $icv = $this->foregroundColor; // fg and bg pattern colors $icv |= $this->backgroundColor << 7; - $border1 = self::mapBorderStyle($this->_style->getBorders()->getLeft()->getBorderStyle()); // Border line style and color - $border1 |= self::mapBorderStyle($this->_style->getBorders()->getRight()->getBorderStyle()) << 4; - $border1 |= self::mapBorderStyle($this->_style->getBorders()->getTop()->getBorderStyle()) << 8; - $border1 |= self::mapBorderStyle($this->_style->getBorders()->getBottom()->getBorderStyle()) << 12; + $border1 = self::mapBorderStyle($this->style->getBorders()->getLeft()->getBorderStyle()); // Border line style and color + $border1 |= self::mapBorderStyle($this->style->getBorders()->getRight()->getBorderStyle()) << 4; + $border1 |= self::mapBorderStyle($this->style->getBorders()->getTop()->getBorderStyle()) << 8; + $border1 |= self::mapBorderStyle($this->style->getBorders()->getBottom()->getBorderStyle()) << 12; $border1 |= $this->leftBorderColor << 16; $border1 |= $this->rightBorderColor << 23; - $diagonalDirection = $this->_style->getBorders()->getDiagonalDirection(); + $diagonalDirection = $this->style->getBorders()->getDiagonalDirection(); $diag_tl_to_rb = $diagonalDirection == Borders::DIAGONAL_BOTH - || $diagonalDirection == Borders::DIAGONAL_DOWN; + || $diagonalDirection == Borders::DIAGONAL_DOWN; $diag_tr_to_lb = $diagonalDirection == Borders::DIAGONAL_BOTH - || $diagonalDirection == Borders::DIAGONAL_UP; + || $diagonalDirection == Borders::DIAGONAL_UP; $border1 |= $diag_tl_to_rb << 30; $border1 |= $diag_tr_to_lb << 31; $border2 = $this->topBorderColor; // Border color $border2 |= $this->bottomBorderColor << 7; - $border2 |= $this->_diag_color << 14; - $border2 |= self::mapBorderStyle($this->_style->getBorders()->getDiagonal()->getBorderStyle()) << 21; - $border2 |= self::mapFillType($this->_style->getFill()->getFillType()) << 26; + $border2 |= $this->diagColor << 14; + $border2 |= self::mapBorderStyle($this->style->getBorders()->getDiagonal()->getBorderStyle()) << 21; + $border2 |= self::mapFillType($this->style->getFill()->getFillType()) << 26; $header = pack('vv', $record, $length); //BIFF8 options: identation, shrinkToFit and text direction - $biff8_options = $this->_style->getAlignment()->getIndent(); - $biff8_options |= (int) $this->_style->getAlignment()->getShrinkToFit() << 4; + $biff8_options = $this->style->getAlignment()->getIndent(); + $biff8_options |= (int) $this->style->getAlignment()->getShrinkToFit() << 4; $data = pack('vvvC', $ifnt, $ifmt, $style, $align); - $data .= pack('CCC', self::mapTextRotation($this->_style->getAlignment()->getTextRotation()), $biff8_options, $used_attrib); + $data .= pack('CCC', self::mapTextRotation($this->style->getAlignment()->getTextRotation()), $biff8_options, $used_attrib); $data .= pack('VVv', $border1, $border2, $icv); return $header . $data; @@ -300,7 +315,7 @@ class Xf */ public function setDiagColor($colorIndex): void { - $this->_diag_color = $colorIndex; + $this->diagColor = $colorIndex; } /** diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php index 583b262c..19da32c4 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php @@ -219,10 +219,12 @@ class Chart extends WriterPart $chartTypes = self::getChartType($plotArea); $catIsMultiLevelSeries = $valIsMultiLevelSeries = false; $plotGroupingType = ''; + $chartType = null; foreach ($chartTypes as $chartType) { $objWriter->startElement('c:' . $chartType); $groupCount = $plotArea->getPlotGroupCount(); + $plotGroup = null; for ($i = 0; $i < $groupCount; ++$i) { $plotGroup = $plotArea->getPlotGroupByIndex($i); $groupType = $plotGroup->getPlotType(); @@ -244,7 +246,7 @@ class Chart extends WriterPart $this->writeDataLabels($objWriter, $layout); - if ($chartType === DataSeries::TYPE_LINECHART) { + if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) { // Line only, Line3D can't be smoothed $objWriter->startElement('c:smooth'); $objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine()); @@ -1079,6 +1081,7 @@ class Chart extends WriterPart } } + $plotSeriesIdx = 0; foreach ($plotSeriesOrder as $plotSeriesIdx => $plotSeriesRef) { $objWriter->startElement('c:ser'); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php index f1bc51f3..2e52a5d7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime; -use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Weekday; +use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\WeekDay; class WeekDayTest extends AllSetupTeardown { @@ -28,8 +28,8 @@ class WeekDayTest extends AllSetupTeardown public function testWEEKDAYwith1904Calendar(): void { self::setMac1904(); - self::assertEquals(7, Weekday::funcWeekDay('1904-01-02')); - self::assertEquals(6, Weekday::funcWeekDay('1904-01-01')); - self::assertEquals(6, Weekday::funcWeekDay(null)); + self::assertEquals(7, WeekDay::funcWeekDay('1904-01-02')); + self::assertEquals(6, WeekDay::funcWeekDay('1904-01-01')); + self::assertEquals(6, WeekDay::funcWeekDay(null)); } } diff --git a/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php b/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php index f98ff7e1..c32c5743 100644 --- a/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php @@ -37,7 +37,7 @@ class XmlScannerTest extends TestCase self::assertEquals($expectedResult, $result); // php 8.+ deprecated libxml_disable_entity_loader() - It's on by default - if (\PHP_VERSION_ID < 80000) { + if (isset($oldDisableEntityLoaderState)) { libxml_disable_entity_loader($oldDisableEntityLoaderState); } } From dd74dd7fcfc21c81a0a25796d2d9e6c491eda63d Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 3 Apr 2021 17:10:40 +0200 Subject: [PATCH 153/187] Let's start with some appeasements to phpstan, just to reduce the baseline (#1983) * Let's start with some appeasements to phpstan, just to reduce the baseline * Appeasements to phpstan, taking the number of reported errors down to just 61 --- .../Calculation/Database/DMax.php | 2 +- .../Calculation/Database/DMin.php | 2 +- .../Calculation/Database/DProduct.php | 2 +- .../Calculation/Database/DStDev.php | 2 +- .../Calculation/Database/DStDevP.php | 2 +- .../Calculation/Database/DSum.php | 2 +- .../Calculation/Database/DVar.php | 2 +- .../Calculation/Database/DVarP.php | 2 +- .../Calculation/DateTimeExcel/Days360.php | 26 +-- .../Calculation/Engineering.php | 42 ++--- .../Calculation/Engineering/BesselI.php | 12 +- .../Calculation/Engineering/BesselJ.php | 11 +- .../Calculation/Engineering/BesselK.php | 11 +- .../Calculation/Engineering/BesselY.php | 11 +- .../Calculation/Engineering/Complex.php | 8 +- .../Calculation/Engineering/Erf.php | 8 +- .../Calculation/Engineering/ErfC.php | 2 +- src/PhpSpreadsheet/Calculation/Financial.php | 48 ++--- .../Calculation/Financial/Amortization.php | 36 ++-- .../Calculation/Financial/Coupons.php | 174 +++++++++--------- .../Calculation/Financial/Depreciation.php | 42 ++--- .../Calculation/Financial/Dollar.php | 8 +- .../Calculation/Financial/InterestRate.php | 8 +- .../Financial/Securities/AccruedInterest.php | 48 +++-- .../Financial/Securities/Price.php | 52 +++--- .../Calculation/Financial/TreasuryBill.php | 6 +- src/PhpSpreadsheet/Calculation/LookupRef.php | 4 +- .../Calculation/LookupRef/Address.php | 22 +-- .../Calculation/Statistical.php | 62 +++---- .../Calculation/Statistical/Confidence.php | 6 +- .../Statistical/Distributions/Beta.php | 34 ++-- .../Statistical/Distributions/Binomial.php | 31 ++-- .../Statistical/Distributions/ChiSquared.php | 18 +- .../Statistical/Distributions/Exponential.php | 6 +- .../Statistical/Distributions/F.php | 9 +- .../Statistical/Distributions/Fisher.php | 12 +- .../Statistical/Distributions/Gamma.php | 18 +- .../Distributions/HyperGeometric.php | 8 +- .../Statistical/Distributions/LogNormal.php | 22 +-- .../Statistical/Distributions/Normal.php | 14 +- .../Statistical/Distributions/Poisson.php | 6 +- .../Distributions/StandardNormal.php | 15 +- .../Statistical/Distributions/StudentT.php | 12 +- .../Statistical/Distributions/Weibull.php | 8 +- .../Calculation/Statistical/Percentiles.php | 14 +- .../Calculation/Statistical/Permutations.php | 12 +- .../Calculation/Statistical/Trends.php | 14 +- src/PhpSpreadsheet/Calculation/TextData.php | 4 +- .../Calculation/TextData/CaseConvert.php | 8 +- .../Calculation/TextData/CharacterConvert.php | 4 +- .../Calculation/TextData/Extract.php | 14 +- .../Calculation/TextData/Format.php | 24 +-- .../Calculation/TextData/Replace.php | 16 +- .../Calculation/TextData/Search.php | 12 +- .../Calculation/TextData/Text.php | 6 +- .../Calculation/TextData/Trim.php | 4 +- .../Calculation/CalculationTest.php | 4 +- .../Functions/DateTime/TimeValueTest.php | 2 +- .../Functions/Logical/IfErrorTest.php | 4 +- .../Functions/Logical/IfNaTest.php | 4 +- .../Functions/MathTrig/EvenTest.php | 2 +- .../Functions/MathTrig/FactDoubleTest.php | 2 +- .../Functions/MathTrig/OddTest.php | 2 +- .../Functions/MathTrig/SignTest.php | 2 +- .../Functions/MathTrig/SqrtPiTest.php | 2 +- .../Functions/Statistical/FisherInvTest.php | 2 +- .../Functions/Statistical/FisherTest.php | 2 +- .../Functions/Statistical/GammaLnTest.php | 2 +- .../Functions/TextData/CharTest.php | 2 +- .../Functions/TextData/CleanTest.php | 2 +- .../Functions/TextData/CodeTest.php | 2 +- .../Functions/TextData/LeftTest.php | 2 +- .../Functions/TextData/LenTest.php | 2 +- .../Functions/TextData/LowerTest.php | 4 +- .../Functions/TextData/MidTest.php | 2 +- .../Functions/TextData/ProperTest.php | 4 +- .../Functions/TextData/RightTest.php | 2 +- .../Calculation/Functions/TextData/TTest.php | 2 +- .../Functions/TextData/TrimTest.php | 2 +- .../Functions/TextData/UpperTest.php | 4 +- .../Functions/TextData/ValueTest.php | 2 +- 81 files changed, 534 insertions(+), 536 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Database/DMax.php b/src/PhpSpreadsheet/Calculation/Database/DMax.php index 6cf2f20d..e84a0bfc 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DMax.php +++ b/src/PhpSpreadsheet/Calculation/Database/DMax.php @@ -30,7 +30,7 @@ class DMax extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DMin.php b/src/PhpSpreadsheet/Calculation/Database/DMin.php index 5668bcf6..4398a7c3 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DMin.php +++ b/src/PhpSpreadsheet/Calculation/Database/DMin.php @@ -30,7 +30,7 @@ class DMin extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DProduct.php b/src/PhpSpreadsheet/Calculation/Database/DProduct.php index f02eb196..4515da24 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DProduct.php +++ b/src/PhpSpreadsheet/Calculation/Database/DProduct.php @@ -29,7 +29,7 @@ class DProduct extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DStDev.php b/src/PhpSpreadsheet/Calculation/Database/DStDev.php index cfc7e952..7ec42bc4 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DStDev.php +++ b/src/PhpSpreadsheet/Calculation/Database/DStDev.php @@ -30,7 +30,7 @@ class DStDev extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DStDevP.php b/src/PhpSpreadsheet/Calculation/Database/DStDevP.php index 2a04c5d9..cbe241f0 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DStDevP.php +++ b/src/PhpSpreadsheet/Calculation/Database/DStDevP.php @@ -30,7 +30,7 @@ class DStDevP extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DSum.php b/src/PhpSpreadsheet/Calculation/Database/DSum.php index 4f784e19..e7e28a4a 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DSum.php +++ b/src/PhpSpreadsheet/Calculation/Database/DSum.php @@ -29,7 +29,7 @@ class DSum extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string + * @return null|float|string */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DVar.php b/src/PhpSpreadsheet/Calculation/Database/DVar.php index c70da073..0a998c03 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DVar.php +++ b/src/PhpSpreadsheet/Calculation/Database/DVar.php @@ -30,7 +30,7 @@ class DVar extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string (string if result is an error) + * @return null|float|string (string if result is an error) */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/Database/DVarP.php b/src/PhpSpreadsheet/Calculation/Database/DVarP.php index f22f2cca..77acbdfc 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DVarP.php +++ b/src/PhpSpreadsheet/Calculation/Database/DVarP.php @@ -30,7 +30,7 @@ class DVarP extends DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return float|string (string if result is an error) + * @return null|float|string (string if result is an error) */ public static function evaluate($database, $field, $criteria) { diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php index b90bc367..18a1abc8 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php @@ -19,20 +19,20 @@ class Days360 * DAYS360(startDate,endDate[,method]) * * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer), - * PHP DateTime object, or a standard date string + * PHP DateTime object, or a standard date string * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), - * PHP DateTime object, or a standard date string - * @param mixed (bool) $method US or European Method - * FALSE or omitted: U.S. (NASD) method. If the starting date is - * the last day of a month, it becomes equal to the 30th of the - * same month. If the ending date is the last day of a month and - * the starting date is earlier than the 30th of a month, the - * ending date becomes equal to the 1st of the next month; - * otherwise the ending date becomes equal to the 30th of the - * same month. - * TRUE: European method. Starting dates and ending dates that - * occur on the 31st of a month become equal to the 30th of the - * same month. + * PHP DateTime object, or a standard date string + * @param mixed $method US or European Method as a bool + * FALSE or omitted: U.S. (NASD) method. If the starting date is + * the last day of a month, it becomes equal to the 30th of the + * same month. If the ending date is the last day of a month and + * the starting date is earlier than the 30th of a month, the + * ending date becomes equal to the 1st of the next month; + * otherwise the ending date becomes equal to the 30th of the + * same month. + * TRUE: European method. Starting dates and ending dates that + * occur on the 31st of a month become equal to the 30th of the + * same month. * * @return int|string Number of days between start date and end date */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 229607e2..7584556a 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -156,7 +156,7 @@ class Engineering * * @see Use the toDecimal() method in the Engineering\ConvertBinary class instead * - * @param string $x The binary number (as a string) that you want to convert. The number + * @param mixed $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant * bit of number is the sign bit. The remaining 9 bits are magnitude bits. * Negative numbers are represented using two's-complement notation. @@ -182,13 +182,13 @@ class Engineering * * @see Use the toHex() method in the Engineering\ConvertBinary class instead * - * @param string $x The binary number (as a string) that you want to convert. The number + * @param mixed $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant * bit of number is the sign bit. The remaining 9 bits are magnitude bits. * Negative numbers are represented using two's-complement notation. * If number is not a valid binary number, or if number contains more than * 10 characters (10 bits), BIN2HEX returns the #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, BIN2HEX uses the + * @param mixed $places The number of characters to use. If places is omitted, BIN2HEX uses the * minimum number of characters necessary. Places is useful for padding the * return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -214,13 +214,13 @@ class Engineering * * @see Use the toOctal() method in the Engineering\ConvertBinary class instead * - * @param string $x The binary number (as a string) that you want to convert. The number + * @param mixed $x The binary number (as a string) that you want to convert. The number * cannot contain more than 10 characters (10 bits). The most significant * bit of number is the sign bit. The remaining 9 bits are magnitude bits. * Negative numbers are represented using two's-complement notation. * If number is not a valid binary number, or if number contains more than * 10 characters (10 bits), BIN2OCT returns the #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, BIN2OCT uses the + * @param mixed $places The number of characters to use. If places is omitted, BIN2OCT uses the * minimum number of characters necessary. Places is useful for padding the * return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -246,7 +246,7 @@ class Engineering * * @see Use the toBinary() method in the Engineering\ConvertDecimal class instead * - * @param string $x The decimal integer you want to convert. If number is negative, + * @param mixed $x The decimal integer you want to convert. If number is negative, * valid place values are ignored and DEC2BIN returns a 10-character * (10-bit) binary number in which the most significant bit is the sign * bit. The remaining 9 bits are magnitude bits. Negative numbers are @@ -256,7 +256,7 @@ class Engineering * If number is nonnumeric, DEC2BIN returns the #VALUE! error value. * If DEC2BIN requires more than places characters, it returns the #NUM! * error value. - * @param int $places The number of characters to use. If places is omitted, DEC2BIN uses + * @param mixed $places The number of characters to use. If places is omitted, DEC2BIN uses * the minimum number of characters necessary. Places is useful for * padding the return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -282,7 +282,7 @@ class Engineering * * @see Use the toHex() method in the Engineering\ConvertDecimal class instead * - * @param string $x The decimal integer you want to convert. If number is negative, + * @param mixed $x The decimal integer you want to convert. If number is negative, * places is ignored and DEC2HEX returns a 10-character (40-bit) * hexadecimal number in which the most significant bit is the sign * bit. The remaining 39 bits are magnitude bits. Negative numbers @@ -292,7 +292,7 @@ class Engineering * If number is nonnumeric, DEC2HEX returns the #VALUE! error value. * If DEC2HEX requires more than places characters, it returns the * #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, DEC2HEX uses + * @param mixed $places The number of characters to use. If places is omitted, DEC2HEX uses * the minimum number of characters necessary. Places is useful for * padding the return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -318,7 +318,7 @@ class Engineering * * @see Use the toOctal() method in the Engineering\ConvertDecimal class instead * - * @param string $x The decimal integer you want to convert. If number is negative, + * @param mixed $x The decimal integer you want to convert. If number is negative, * places is ignored and DEC2OCT returns a 10-character (30-bit) * octal number in which the most significant bit is the sign bit. * The remaining 29 bits are magnitude bits. Negative numbers are @@ -328,7 +328,7 @@ class Engineering * If number is nonnumeric, DEC2OCT returns the #VALUE! error value. * If DEC2OCT requires more than places characters, it returns the * #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, DEC2OCT uses + * @param mixed $places The number of characters to use. If places is omitted, DEC2OCT uses * the minimum number of characters necessary. Places is useful for * padding the return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -354,7 +354,7 @@ class Engineering * * @see Use the toBinary() method in the Engineering\ConvertHex class instead * - * @param string $x the hexadecimal number you want to convert. + * @param mixed $x the hexadecimal number (as a string) that you want to convert. * Number cannot contain more than 10 characters. * The most significant bit of number is the sign bit (40th bit from the right). * The remaining 9 bits are magnitude bits. @@ -364,7 +364,7 @@ class Engineering * and if number is positive, it cannot be greater than 1FF. * If number is not a valid hexadecimal number, HEX2BIN returns the #NUM! error value. * If HEX2BIN requires more than places characters, it returns the #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, + * @param mixed $places The number of characters to use. If places is omitted, * HEX2BIN uses the minimum number of characters necessary. Places * is useful for padding the return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -390,7 +390,7 @@ class Engineering * * @see Use the toDecimal() method in the Engineering\ConvertHex class instead * - * @param string $x The hexadecimal number you want to convert. This number cannot + * @param mixed $x The hexadecimal number (as a string) that you want to convert. This number cannot * contain more than 10 characters (40 bits). The most significant * bit of number is the sign bit. The remaining 39 bits are magnitude * bits. Negative numbers are represented using two's-complement @@ -417,7 +417,7 @@ class Engineering * * @see Use the toOctal() method in the Engineering\ConvertHex class instead * - * @param string $x The hexadecimal number you want to convert. Number cannot + * @param mixed $x The hexadecimal number (as a string) that you want to convert. Number cannot * contain more than 10 characters. The most significant bit of * number is the sign bit. The remaining 39 bits are magnitude * bits. Negative numbers are represented using two's-complement @@ -430,7 +430,7 @@ class Engineering * the #NUM! error value. * If HEX2OCT requires more than places characters, it returns * the #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, HEX2OCT + * @param mixed $places The number of characters to use. If places is omitted, HEX2OCT * uses the minimum number of characters necessary. Places is * useful for padding the return value with leading 0s (zeros). * If places is not an integer, it is truncated. @@ -457,7 +457,7 @@ class Engineering * * @see Use the toBinary() method in the Engineering\ConvertOctal class instead * - * @param string $x The octal number you want to convert. Number may not + * @param mixed $x The octal number you want to convert. Number may not * contain more than 10 characters. The most significant * bit of number is the sign bit. The remaining 29 bits * are magnitude bits. Negative numbers are represented @@ -470,7 +470,7 @@ class Engineering * the #NUM! error value. * If OCT2BIN requires more than places characters, it * returns the #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, + * @param mixed $places The number of characters to use. If places is omitted, * OCT2BIN uses the minimum number of characters necessary. * Places is useful for padding the return value with * leading 0s (zeros). @@ -499,7 +499,7 @@ class Engineering * * @see Use the toDecimal() method in the Engineering\ConvertOctal class instead * - * @param string $x The octal number you want to convert. Number may not contain + * @param mixed $x The octal number you want to convert. Number may not contain * more than 10 octal characters (30 bits). The most significant * bit of number is the sign bit. The remaining 29 bits are * magnitude bits. Negative numbers are represented using @@ -526,7 +526,7 @@ class Engineering * * @see Use the toHex() method in the Engineering\ConvertOctal class instead * - * @param string $x The octal number you want to convert. Number may not contain + * @param mixed $x The octal number you want to convert. Number may not contain * more than 10 octal characters (30 bits). The most significant * bit of number is the sign bit. The remaining 29 bits are * magnitude bits. Negative numbers are represented using @@ -537,7 +537,7 @@ class Engineering * #NUM! error value. * If OCT2HEX requires more than places characters, it returns * the #NUM! error value. - * @param int $places The number of characters to use. If places is omitted, OCT2HEX + * @param mixed $places The number of characters to use. If places is omitted, OCT2HEX * uses the minimum number of characters necessary. Places is useful * for padding the return value with leading 0s (zeros). * If places is not an integer, it is truncated. diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php index 23183612..89977101 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php @@ -21,12 +21,12 @@ class BesselI * NOTE: The MS Excel implementation of the BESSELI function is still not accurate. * This code provides a more accurate calculation * - * @param mixed (float) $x The value at which to evaluate the function. - * If x is nonnumeric, BESSELI returns the #VALUE! error value. - * @param mixed (int) $ord The order of the Bessel function. - * If ord is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELI returns the #VALUE! error value. - * If $ord < 0, BESSELI returns the #NUM! error value. + * @param mixed $x A float value at which to evaluate the function. + * If x is nonnumeric, BESSELI returns the #VALUE! error value. + * @param mixed $ord The integer order of the Bessel function. + * If ord is not an integer, it is truncated. + * If $ord is nonnumeric, BESSELI returns the #VALUE! error value. + * If $ord < 0, BESSELI returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php index ca9ff4f7..e16c1519 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php @@ -20,11 +20,12 @@ class BesselJ * NOTE: The MS Excel implementation of the BESSELJ function is still not accurate, particularly for higher order * values with x < -8 and x > 8. This code provides a more accurate calculation * - * @param mixed (float) $x The value at which to evaluate the function. - * If x is nonnumeric, BESSELJ returns the #VALUE! error value. - * @param mixed (int) $ord The order of the Bessel function. If n is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value. - * If $ord < 0, BESSELJ returns the #NUM! error value. + * @param mixed $x A float value at which to evaluate the function. + * If x is nonnumeric, BESSELJ returns the #VALUE! error value. + * @param mixed $ord The integer order of the Bessel function. + * If ord is not an integer, it is truncated. + * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value. + * If $ord < 0, BESSELJ returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php index faba191f..57794e03 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php @@ -18,11 +18,12 @@ class BesselK * Excel Function: * BESSELK(x,ord) * - * @param mixed (float) $x The value at which to evaluate the function. - * If x is nonnumeric, BESSELK returns the #VALUE! error value. - * @param mixed (int) $ord The order of the Bessel function. If n is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELK returns the #VALUE! error value. - * If $ord < 0, BESSELK returns the #NUM! error value. + * @param mixed $x A float value at which to evaluate the function. + * If x is nonnumeric, BESSELK returns the #VALUE! error value. + * @param mixed $ord The integer order of the Bessel function. + * If ord is not an integer, it is truncated. + * If $ord is nonnumeric, BESSELK returns the #VALUE! error value. + * If $ord < 0, BESSELKI returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php index 1eed5a54..19932c64 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php @@ -17,11 +17,12 @@ class BesselY * Excel Function: * BESSELY(x,ord) * - * @param mixed (float) $x The value at which to evaluate the function. - * If x is nonnumeric, BESSELY returns the #VALUE! error value. - * @param mixed (int) $ord The order of the Bessel function. If n is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELY returns the #VALUE! error value. - * If $ord < 0, BESSELY returns the #NUM! error value. + * @param mixed $x A float value at which to evaluate the function. + * If x is nonnumeric, BESSELY returns the #VALUE! error value. + * @param mixed $ord The integer order of the Bessel function. + * If ord is not an integer, it is truncated. + * If $ord is nonnumeric, BESSELY returns the #VALUE! error value. + * If $ord < 0, BESSELY returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php index a1a64768..f2718e4a 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php @@ -19,10 +19,10 @@ class Complex * Excel Function: * COMPLEX(realNumber,imaginary[,suffix]) * - * @param mixed (float) $realNumber the real coefficient of the complex number - * @param mixed (float) $imaginary the imaginary coefficient of the complex number - * @param mixed (string) $suffix The suffix for the imaginary component of the complex number. - * If omitted, the suffix is assumed to be "i". + * @param mixed $realNumber the real float coefficient of the complex number + * @param mixed $imaginary the imaginary float coefficient of the complex number + * @param mixed $suffix The character suffix for the imaginary component of the complex number. + * If omitted, the suffix is assumed to be "i". * * @return string */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Erf.php b/src/PhpSpreadsheet/Calculation/Engineering/Erf.php index a5df425e..db87ec0d 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Erf.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Erf.php @@ -21,9 +21,9 @@ class Erf * Excel Function: * ERF(lower[,upper]) * - * @param mixed (float) $lower lower bound for integrating ERF - * @param mixed (float) $upper upper bound for integrating ERF. - * If omitted, ERF integrates between zero and lower_limit + * @param mixed $lower Lower bound float for integrating ERF + * @param mixed $upper Upper bound float for integrating ERF. + * If omitted, ERF integrates between zero and lower_limit * * @return float|string */ @@ -52,7 +52,7 @@ class Erf * Excel Function: * ERF.PRECISE(limit) * - * @param mixed (float) $limit bound for integrating ERF + * @param mixed $limit Float bound for integrating ERF, other bound is zero * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php b/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php index 31c3bd75..c57a28f4 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ErfC.php @@ -19,7 +19,7 @@ class ErfC * Excel Function: * ERFC(x) * - * @param float $value The lower bound for integrating ERFC + * @param mixed $value The float lower bound for integrating ERFC * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 547ad6b3..984d31bf 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -49,21 +49,21 @@ class Financial * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date * when the security is traded to the buyer. - * @param mixed (float) $rate the security's annual coupon rate - * @param mixed (float) $par The security's par value. + * @param mixed $rate the security's annual coupon rate + * @param mixed $par The security's par value. * If you omit par, ACCRINT uses $1,000. - * @param mixed (int) $frequency The number of coupon payments per year. + * @param mixed $frequency The number of coupon payments per year. * Valid frequency values are: * 1 Annual * 2 Semi-Annual * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. + * @param mixed $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 * 3 Actual/365 * 4 European 30/360 - * @param mixed (bool) $calcMethod + * @param mixed $calcMethod * If true, use Issue to Settlement * If false, use FirstInterest to Settlement * @@ -106,10 +106,10 @@ class Financial * * @param mixed $issue The security's issue date * @param mixed $settlement The security's settlement (or maturity) date - * @param mixed (float) $rate The security's annual coupon rate - * @param mixed (float) $par The security's par value. + * @param mixed $rate The security's annual coupon rate + * @param mixed $par The security's par value. * If you omit par, ACCRINT uses $1,000. - * @param mixed (int) $basis The type of day count to use. + * @param mixed $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 @@ -876,11 +876,11 @@ class Financial * Excel Function: * IRR(values[,guess]) * - * @param mixed (float[]) $values An array or a reference to cells that contain numbers for which you want + * @param mixed $values An array or a reference to cells that contain numbers for which you want * to calculate the internal rate of return. * Values must contain at least one positive value and one negative value to * calculate the internal rate of return. - * @param mixed (float) $guess A number that you guess is close to the result of IRR + * @param mixed $guess A number that you guess is close to the result of IRR * * @return float|string */ @@ -986,11 +986,11 @@ class Financial * Excel Function: * MIRR(values,finance_rate, reinvestment_rate) * - * @param mixed (float[]) $values An array or a reference to cells that contain a series of payments and - * income occurring at regular intervals. - * Payments are negative value, income is positive values. - * @param mixed (float) $finance_rate The interest rate you pay on the money used in the cash flows - * @param mixed (float) $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them + * @param mixed $values An array or a reference to cells that contain a series of payments and + * income occurring at regular intervals. + * Payments are negative value, income is positive values. + * @param mixed $finance_rate The interest rate you pay on the money used in the cash flows + * @param mixed $reinvestment_rate The interest rate you receive on the cash flows as you reinvest them * * @return float|string Result, or a string containing an error */ @@ -1357,20 +1357,20 @@ class Financial * Excel Function: * RATE(nper,pmt,pv[,fv[,type[,guess]]]) * - * @param mixed (float) $nper The total number of payment periods in an annuity - * @param mixed (float) $pmt The payment made each period and cannot change over the life + * @param mixed $nper The total number of payment periods in an annuity + * @param mixed $pmt The payment made each period and cannot change over the life * of the annuity. * Typically, pmt includes principal and interest but no other * fees or taxes. - * @param mixed (float) $pv The present value - the total amount that a series of future + * @param mixed $pv The present value - the total amount that a series of future * payments is worth now - * @param mixed (float) $fv The future value, or a cash balance you want to attain after + * @param mixed $fv The future value, or a cash balance you want to attain after * the last payment is made. If fv is omitted, it is assumed * to be 0 (the future value of a loan, for example, is 0). - * @param mixed (int) $type A number 0 or 1 and indicates when payments are due: + * @param mixed $type A number 0 or 1 and indicates when payments are due: * 0 or omitted At the end of the period. * 1 At the beginning of the period. - * @param mixed (float) $guess Your guess for what the rate will be. + * @param mixed $guess Your guess for what the rate will be. * If you omit guess, it is assumed to be 10 percent. * * @return float|string @@ -1429,9 +1429,9 @@ class Financial * The security settlement date is the date after the issue 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 mixed (int) $investment The amount invested in the security - * @param mixed (int) $discount The security's discount rate - * @param mixed (int) $basis The type of day count to use. + * @param mixed $investment The amount invested in the security + * @param mixed $discount The security's discount rate + * @param mixed $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual * 2 Actual/360 diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php index 9e838a26..8b901872 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php @@ -25,18 +25,18 @@ class Amortization * Excel Function: * AMORDEGRC(cost,purchased,firstPeriod,salvage,period,rate[,basis]) * - * @param mixed (float) $cost The cost of the asset + * @param mixed $cost The float cost of the asset * @param mixed $purchased Date of the purchase of the asset * @param mixed $firstPeriod Date of the end of the first period * @param mixed $salvage The salvage value at the end of the life of the asset - * @param mixed (float) $period The period - * @param mixed (float) $rate Rate of depreciation - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $period the period (float) + * @param mixed $rate rate of depreciation (float) + * @param mixed $basis The type of day count to use (int). + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string (string containing the error type if there is an error) */ @@ -103,18 +103,18 @@ class Amortization * Excel Function: * AMORLINC(cost,purchased,firstPeriod,salvage,period,rate[,basis]) * - * @param mixed (float) $cost The cost of the asset + * @param mixed $cost The cost of the asset as a float * @param mixed $purchased Date of the purchase of the asset * @param mixed $firstPeriod Date of the end of the first period * @param mixed $salvage The salvage value at the end of the life of the asset - * @param mixed (float) $period The period - * @param mixed (float) $rate Rate of depreciation - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $period The period as a float + * @param mixed $rate Rate of depreciation as float + * @param mixed $basis Integer indicating the type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string (string containing the error type if there is an error) */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php index ce83ccb4..c24b31be 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -27,21 +27,21 @@ class Coupons * COUPDAYBS(settlement,maturity,frequency[,basis]) * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue - * date when the security is traded to the buyer. + * The security settlement date is the date after the issue + * 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 mixed (int) $frequency the number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * The maturity date is the date when the security expires. + * @param mixed $frequency The number of coupon payments per year (int). + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use (int). + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string */ @@ -84,21 +84,21 @@ class Coupons * COUPDAYS(settlement,maturity,frequency[,basis]) * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue - * date when the security is traded to the buyer. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * The maturity date is the date when the security expires. + * @param mixed $frequency The number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use (int). + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string */ @@ -149,21 +149,21 @@ class Coupons * COUPDAYSNC(settlement,maturity,frequency[,basis]) * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue - * date when the security is traded to the buyer. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * The maturity date is the date when the security expires. + * @param mixed $frequency The number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use (int) . + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string */ @@ -207,24 +207,24 @@ class Coupons * COUPNCD(settlement,maturity,frequency[,basis]) * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue - * date when the security is traded to the buyer. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * The maturity date is the date when the security expires. + * @param mixed $frequency The number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use (int). + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag + * depending on the value of the ReturnDateType flag */ public static function COUPNCD($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) { @@ -256,21 +256,21 @@ class Coupons * COUPNUM(settlement,maturity,frequency[,basis]) * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue - * date when the security is traded to the buyer. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * The maturity date is the date when the security expires. + * @param mixed $frequency The number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use (int). + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return int|string */ @@ -293,7 +293,7 @@ class Coupons $yearsBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, 0); - return ceil($yearsBetweenSettlementAndMaturity * $frequency); + return (int) ceil($yearsBetweenSettlementAndMaturity * $frequency); } /** @@ -305,24 +305,24 @@ class Coupons * COUPPCD(settlement,maturity,frequency[,basis]) * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue - * date when the security is traded to the buyer. + * The security settlement date is the date after the issue + * 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 mixed $frequency the number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * The maturity date is the date when the security expires. + * @param mixed $frequency The number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use (int). + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, - * depending on the value of the ReturnDateType flag + * depending on the value of the ReturnDateType flag */ public static function COUPPCD($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) { diff --git a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php index 89dc226c..a918bf7d 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php @@ -22,15 +22,15 @@ class Depreciation * Excel Function: * DB(cost,salvage,life,period[,month]) * - * @param mixed (float) $cost Initial cost of the asset - * @param mixed (float) $salvage Value at the end of the depreciation. - * (Sometimes called the salvage value of the asset) - * @param mixed (int) $life Number of periods over which the asset is depreciated. - * (Sometimes called the useful life of the asset) - * @param mixed (int) $period The period for which you want to calculate the - * depreciation. Period must use the same units as life. - * @param mixed (int) $month Number of months in the first year. If month is omitted, - * it defaults to 12. + * @param mixed $cost Initial cost of the asset + * @param mixed $salvage Value at the end of the depreciation. + * (Sometimes called the salvage value of the asset) + * @param mixed $life Number of periods over which the asset is depreciated. + * (Sometimes called the useful life of the asset) + * @param mixed $period The period for which you want to calculate the + * depreciation. Period must use the same units as life. + * @param mixed $month Number of months in the first year. If month is omitted, + * it defaults to 12. * * @return float|string */ @@ -87,14 +87,14 @@ class Depreciation * Excel Function: * DDB(cost,salvage,life,period[,factor]) * - * @param mixed (float) $cost Initial cost of the asset - * @param mixed (float) $salvage Value at the end of the depreciation. + * @param mixed $cost Initial cost of the asset + * @param mixed $salvage Value at the end of the depreciation. * (Sometimes called the salvage value of the asset) - * @param mixed (int) $life Number of periods over which the asset is depreciated. + * @param mixed $life Number of periods over which the asset is depreciated. * (Sometimes called the useful life of the asset) - * @param mixed (int) $period The period for which you want to calculate the + * @param mixed $period The period for which you want to calculate the * depreciation. Period must use the same units as life. - * @param mixed (float) $factor The rate at which the balance declines. + * @param mixed $factor The rate at which the balance declines. * If factor is omitted, it is assumed to be 2 (the * double-declining balance method). * @@ -139,9 +139,9 @@ class Depreciation * * Returns the straight-line depreciation of an asset for one period * - * @param mixed (float) $cost Initial cost of the asset - * @param mixed (float) $salvage Value at the end of the depreciation - * @param mixed (float) $life Number of periods over which the asset is depreciated + * @param mixed $cost Initial cost of the asset + * @param mixed $salvage Value at the end of the depreciation + * @param mixed $life Number of periods over which the asset is depreciated * * @return float|string Result, or a string containing an error */ @@ -171,10 +171,10 @@ class Depreciation * * Returns the sum-of-years' digits depreciation of an asset for a specified period. * - * @param mixed (float) $cost Initial cost of the asset - * @param mixed (float) $salvage Value at the end of the depreciation - * @param mixed (float) $life Number of periods over which the asset is depreciated - * @param mixed (float) $period Period + * @param mixed $cost Initial cost of the asset + * @param mixed $salvage Value at the end of the depreciation + * @param mixed $life Number of periods over which the asset is depreciated + * @param mixed $period Period * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php index 36326a60..b25b0c2e 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Dollar.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Dollar.php @@ -16,8 +16,8 @@ class Dollar * Excel Function: * DOLLARDE(fractional_dollar,fraction) * - * @param mixed (float) $fractionalDollar Fractional Dollar - * @param mixed (int) $fraction Fraction + * @param mixed $fractionalDollar Fractional Dollar + * @param mixed $fraction Fraction * * @return float|string */ @@ -52,8 +52,8 @@ class Dollar * Excel Function: * DOLLARFR(decimal_dollar,fraction) * - * @param mixed (float) $decimalDollar Decimal Dollar - * @param mixed (int) $fraction Fraction + * @param mixed $decimalDollar Decimal Dollar + * @param mixed $fraction Fraction * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php index ed0fec75..7d66c891 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php +++ b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php @@ -18,8 +18,8 @@ class InterestRate * Excel Function: * EFFECT(nominal_rate,npery) * - * @param mixed (float) $nominalRate Nominal interest rate - * @param mixed (int) $periodsPerYear Number of compounding payments per year + * @param mixed $nominalRate Nominal interest rate as a float + * @param mixed $periodsPerYear Integer number of compounding payments per year * * @return float|string */ @@ -47,8 +47,8 @@ class InterestRate * * Returns the nominal interest rate given the effective rate and the number of compounding payments per year. * - * @param mixed (float) $effectiveRate Effective interest rate - * @param mixed (int) $periodsPerYear Number of compounding payments per year + * @param mixed $effectiveRate Effective interest rate as a float + * @param mixed $periodsPerYear Integer number of compounding payments per year * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php index 726b125a..1875b8b7 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php @@ -27,21 +27,20 @@ class AccruedInterest * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date * when the security is traded to the buyer. - * @param mixed (float) $rate The security's annual coupon rate - * @param mixed (float) $par The security's par value. - * If you omit par, ACCRINT uses $1,000. - * @param mixed (int) $frequency The number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @param mixed $parValue + * @param mixed $rate The security's annual coupon rate + * @param mixed $parValue The security's par value. + * If you omit par, ACCRINT uses $1,000. + * @param mixed $frequency The number of coupon payments per year. + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * @param mixed $calcMethod * * @return float|string Result, or a string containing an error @@ -100,16 +99,15 @@ class AccruedInterest * * @param mixed $issue The security's issue date * @param mixed $settlement The security's settlement (or maturity) date - * @param mixed (float) $rate The security's annual coupon rate - * @param mixed (float) $par The security's par value. - * If you omit par, ACCRINT uses $1,000. - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 - * @param mixed $parValue + * @param mixed $rate The security's annual coupon rate + * @param mixed $parValue The security's par value. + * If you omit par, ACCRINT uses $1,000. + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php index 6b04d6d9..cccdb78b 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php @@ -22,19 +22,19 @@ class Price * is traded to the buyer. * @param mixed $maturity The security's maturity date. * The maturity date is the date when the security expires. - * @param mixed (float) $rate the security's annual coupon rate - * @param mixed (float) $yield the security's annual yield - * @param mixed (float) $redemption The number of coupon payments per year. + * @param mixed $rate the security's annual coupon rate + * @param mixed $yield the security's annual yield + * @param mixed $redemption The number of coupon payments per year. * For annual payments, frequency = 1; * for semiannual, frequency = 2; * for quarterly, frequency = 4. - * @param mixed (int) $frequency - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $frequency + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ @@ -89,14 +89,14 @@ class Price * is traded to the buyer. * @param mixed $maturity The security's maturity date. * The maturity date is the date when the security expires. - * @param mixed (float) $discount The security's discount rate - * @param mixed (float) $redemption The security's redemption value per $100 face value - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $discount The security's discount rate + * @param mixed $redemption The security's redemption value per $100 face value + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ @@ -139,14 +139,14 @@ class Price * @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 mixed (float) $rate The security's interest rate at date of issue - * @param mixed (float) $yield The security's annual yield - * @param mixed (int) $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $rate The security's interest rate at date of issue + * @param mixed $yield The security's annual yield + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php index 8fd47ba6..8f170488 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php +++ b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php @@ -20,7 +20,7 @@ class TreasuryBill * 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 mixed (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 */ @@ -66,7 +66,7 @@ class TreasuryBill * 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 mixed (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 */ @@ -117,7 +117,7 @@ class TreasuryBill * 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 mixed (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|string */ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef.php b/src/PhpSpreadsheet/Calculation/LookupRef.php index 4a1bcb06..6a89f7da 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef.php @@ -148,8 +148,8 @@ class LookupRef * Excel Function: * =HYPERLINK(linkURL,displayName) * - * @param mixed (string) $linkURL Value to check, is also the value returned when no error - * @param mixed (string) $displayName Value to return when testValue is an error condition + * @param mixed $linkURL URL Value to check, is also the value returned when no error + * @param mixed $displayName String Value to return when testValue is an error condition * @param Cell $pCell The cell to set the hyperlink in * * @return mixed The value of $displayName (or $linkURL if $displayName was blank) diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php index daaebea2..c217a1e4 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Address.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Address.php @@ -23,17 +23,17 @@ class Address * Excel Function: * =ADDRESS(row, column, [relativity], [referenceStyle], [sheetText]) * - * @param mixed $row Row number to use in the cell reference - * @param mixed $column Column number to use in the cell reference - * @param mixed (int) $relativity Flag indicating the type of reference to return - * 1 or omitted Absolute - * 2 Absolute row; relative column - * 3 Relative row; absolute column - * 4 Relative - * @param mixed (bool) $referenceStyle A logical value that specifies the A1 or R1C1 reference style. - * TRUE or omitted ADDRESS returns an A1-style reference - * FALSE ADDRESS returns an R1C1-style reference - * @param mixed (string) $sheetName Optional Name of worksheet to use + * @param mixed $row Row number (integer) to use in the cell reference + * @param mixed $column Column number (integer) to use in the cell reference + * @param mixed $relativity Integer flag indicating the type of reference to return + * 1 or omitted Absolute + * 2 Absolute row; relative column + * 3 Relative row; absolute column + * 4 Relative + * @param mixed $referenceStyle A logical (boolean) value that specifies the A1 or R1C1 reference style. + * TRUE or omitted ADDRESS returns an A1-style reference + * FALSE ADDRESS returns an R1C1-style reference + * @param mixed $sheetName Optional Name of worksheet to use * * @return string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 3e90b21d..003f06be 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -172,10 +172,10 @@ class Statistical * @see Statistical\Distributions\Binomial::distribution() * Use the distribution() method in the Statistical\Distributions\Binomial class instead * - * @param mixed (float) $value Number of successes in trials - * @param mixed (float) $trials Number of trials - * @param mixed (float) $probability Probability of success on each trial - * @param mixed (bool) $cumulative + * @param mixed $value Number of successes in trials + * @param mixed $trials Number of trials + * @param mixed $probability Probability of success on each trial + * @param mixed $cumulative * * @return float|string */ @@ -790,10 +790,10 @@ class Statistical * @see Statistical\Distributions\HyperGeometric::distribution() * Use the distribution() method in the Statistical\Distributions\HyperGeometric class instead * - * @param mixed (int) $sampleSuccesses Number of successes in the sample - * @param mixed (int) $sampleNumber Size of the sample - * @param mixed (int) $populationSuccesses Number of successes in the population - * @param mixed (int) $populationNumber Population size + * @param mixed $sampleSuccesses Number of successes in the sample + * @param mixed $sampleNumber Size of the sample + * @param mixed $populationSuccesses Number of successes in the population + * @param mixed $populationNumber Population size * * @return float|string */ @@ -1221,9 +1221,9 @@ class Statistical * @see Statistical\Distributions\Binomial::negative() * Use the negative() method in the Statistical\Distributions\Binomial class instead * - * @param mixed (float) $failures Number of Failures - * @param mixed (float) $successes Threshold number of Successes - * @param mixed (float) $probability Probability of success on each trial + * @param mixed $failures Number of Failures + * @param mixed $successes Threshold number of Successes + * @param mixed $probability Probability of success on each trial * * @return float|string The result, or a string containing an error */ @@ -1244,10 +1244,10 @@ class Statistical * @see Statistical\Distributions\Normal::distribution() * Use the distribution() method in the Statistical\Distributions\Normal class instead * - * @param mixed (float) $value - * @param mixed (float) $mean Mean Value - * @param mixed (float) $stdDev Standard Deviation - * @param mixed (bool) $cumulative + * @param mixed $value + * @param mixed $mean Mean Value + * @param mixed $stdDev Standard Deviation + * @param mixed $cumulative * * @return float|string The result, or a string containing an error */ @@ -1266,9 +1266,9 @@ class Statistical * @see Statistical\Distributions\Normal::inverse() * Use the inverse() method in the Statistical\Distributions\Normal class instead * - * @param mixed (float) $probability - * @param mixed (float) $mean Mean Value - * @param mixed (float) $stdDev Standard Deviation + * @param mixed $probability + * @param mixed $mean Mean Value + * @param mixed $stdDev Standard Deviation * * @return float|string The result, or a string containing an error */ @@ -1289,7 +1289,7 @@ class Statistical * @see Statistical\Distributions\StandardNormal::cumulative() * Use the cumulative() method in the Statistical\Distributions\StandardNormal class instead * - * @param mixed (float) $value + * @param mixed $value * * @return float|string The result, or a string containing an error */ @@ -1310,8 +1310,8 @@ class Statistical * @see Statistical\Distributions\StandardNormal::distribution() * Use the distribution() method in the Statistical\Distributions\StandardNormal class instead * - * @param mixed (float) $value - * @param mixed (bool) $cumulative + * @param mixed $value + * @param mixed $cumulative * * @return float|string The result, or a string containing an error */ @@ -1330,7 +1330,7 @@ class Statistical * @see Statistical\Distributions\StandardNormal::inverse() * Use the inverse() method in the Statistical\Distributions\StandardNormal class instead * - * @param mixed (float) $value + * @param mixed $value * * @return float|string The result, or a string containing an error */ @@ -1374,9 +1374,9 @@ class Statistical * @see Statistical\Percentiles::PERCENTRANK() * Use the PERCENTRANK() method in the Statistical\Percentiles class instead * - * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers - * @param mixed (int) $value the number whose rank you want to find - * @param mixed (int) $significance the number of significant digits for the returned percentage value + * @param mixed $valueSet An array of, or a reference to, a list of numbers + * @param mixed $value the number whose rank you want to find + * @param mixed $significance the number of significant digits for the returned percentage value * * @return float|string (string if result is an error) */ @@ -1421,9 +1421,9 @@ class Statistical * @see Statistical\Distributions\Poisson::distribution() * Use the distribution() method in the Statistical\Distributions\Poisson class instead * - * @param mixed (float) $value - * @param mixed (float) $mean Mean Value - * @param mixed (bool) $cumulative + * @param mixed $value + * @param mixed $mean Mean Value + * @param mixed $cumulative * * @return float|string The result, or a string containing an error */ @@ -1464,9 +1464,9 @@ class Statistical * @see Statistical\Percentiles::RANK() * Use the RANK() method in the Statistical\Percentiles class instead * - * @param mixed (float) $value the number whose rank you want to find - * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers - * @param mixed (int) $order Order to sort the values in the value set + * @param mixed $value the number whose rank you want to find + * @param mixed $valueSet An array of, or a reference to, a list of numbers + * @param mixed $order Order to sort the values in the value set * * @return float|string The result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php index 40adc9e3..7d354dfe 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Confidence.php @@ -14,9 +14,9 @@ class Confidence * * Returns the confidence interval for a population mean * - * @param mixed (float) $alpha - * @param mixed (float) $stdDev Standard Deviation - * @param mixed (float) $size + * @param mixed $alpha As a float + * @param mixed $stdDev Standard Deviation as a float + * @param mixed $size As an integer * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php index 30b8d02a..95446c45 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php @@ -20,11 +20,11 @@ class Beta * * Returns the beta distribution. * - * @param mixed (float) $value Value at which you want to evaluate the distribution - * @param mixed (float) $alpha Parameter to the distribution - * @param mixed (float) $beta Parameter to the distribution - * @param mixed (float) $rMin - * @param mixed (float) $rMax + * @param mixed $value Float value at which you want to evaluate the distribution + * @param mixed $alpha Parameter to the distribution as a float + * @param mixed $beta Parameter to the distribution as a float + * @param mixed $rMin as an float + * @param mixed $rMax as an float * * @return float|string */ @@ -66,11 +66,11 @@ class Beta * * Returns the inverse of the Beta distribution. * - * @param mixed (float) $probability Probability at which you want to evaluate the distribution - * @param mixed (float) $alpha Parameter to the distribution - * @param mixed (float) $beta Parameter to the distribution - * @param mixed (float) $rMin Minimum value - * @param mixed (float) $rMax Maximum value + * @param mixed $probability Float probability at which you want to evaluate the distribution + * @param mixed $alpha Parameter to the distribution as a float + * @param mixed $beta Parameter to the distribution as a float + * @param mixed $rMin Minimum value as a float + * @param mixed $rMax Maximum value as a float * * @return float|string */ @@ -137,9 +137,9 @@ class Beta * * The computation is based on formulas from Numerical Recipes, Chapter 6.4 (W.H. Press et al, 1992). * - * @param mixed $x require 0<=x<=1 - * @param mixed $p require p>0 - * @param mixed $q require q>0 + * @param float $x require 0<=x<=1 + * @param float $p require p>0 + * @param float $q require q>0 * * @return float 0 if x<0, p<=0, q<=0 or p+q>2.55E305 and 1 if x>1 to avoid errors and over/underflow */ @@ -171,8 +171,8 @@ class Beta /** * The natural logarithm of the beta function. * - * @param mixed $p require p>0 - * @param mixed $q require q>0 + * @param float $p require p>0 + * @param float $q require q>0 * * @return float 0 if p<=0, q<=0 or p+q>2.55E305 to avoid errors and over/underflow * @@ -198,10 +198,6 @@ class Beta * Based on an idea from Numerical Recipes (W.H. Press et al, 1992). * * @author Jaco van Kooten - * - * @param mixed $x - * @param mixed $p - * @param mixed $q */ private static function betaFraction(float $x, float $p, float $q): float { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php index 2ab1fe67..acdda8d3 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php @@ -19,10 +19,10 @@ class Binomial * experiment. For example, BINOMDIST can calculate the probability that two of the next three * babies born are male. * - * @param mixed (int) $value Number of successes in trials - * @param mixed (int) $trials Number of trials - * @param mixed (float) $probability Probability of success on each trial - * @param mixed (bool) $cumulative + * @param mixed $value Integer number of successes in trials + * @param mixed $trials Integer umber of trials + * @param mixed $probability Probability of success on each trial as a float + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string */ @@ -58,10 +58,11 @@ class Binomial * Returns returns the Binomial Distribution probability for the number of successes from a specified number * of trials falling into a specified range. * - * @param mixed (int) $trials Number of trials - * @param mixed (float) $probability Probability of success on each trial - * @param mixed (int) $successes The number of successes in trials - * @param mixed (int) $limit Upper limit for successes in trials + * @param mixed $trials Integer number of trials + * @param mixed $probability Probability of success on each trial as a float + * @param mixed $successes The integer number of successes in trials + * @param mixed $limit Upper limit for successes in trials as null, or an integer + * If null, then this will indicate the same as the number of Successes * * @return float|string */ @@ -105,9 +106,9 @@ class Binomial * distribution, except that the number of successes is fixed, and the number of trials is * variable. Like the binomial, trials are assumed to be independent. * - * @param mixed (float) $failures Number of Failures - * @param mixed (float) $successes Threshold number of Successes - * @param mixed (float) $probability Probability of success on each trial + * @param mixed $failures Number of Failures as an integer + * @param mixed $successes Threshold number of Successes as an integer + * @param mixed $probability Probability of success on each trial as a float * * @return float|string The result, or a string containing an error * @@ -147,9 +148,9 @@ class Binomial * Returns the smallest value for which the cumulative binomial distribution is greater * than or equal to a criterion value * - * @param float $trials number of Bernoulli trials - * @param float $probability probability of a success on each trial - * @param float $alpha criterion value + * @param mixed $trials number of Bernoulli trials as an integer + * @param mixed $probability probability of a success on each trial as a float + * @param mixed $alpha criterion value as a float * * @return int|string */ @@ -174,7 +175,7 @@ class Binomial } $successes = 0; - while (true && $successes <= $trials) { + while ($successes <= $trials) { $result = self::calculateCumulativeBinomial($successes, $trials, $probability); if ($result >= $alpha) { break; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index 3ebe1dc5..efc62f83 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -18,8 +18,8 @@ class ChiSquared * * Returns the one-tailed probability of the chi-squared distribution. * - * @param mixed (float) $value Value for the function - * @param mixed (int) $degrees degrees of freedom + * @param mixed $value Float value for which we want the probability + * @param mixed $degrees Integer degrees of freedom * * @return float|string */ @@ -54,9 +54,9 @@ class ChiSquared * * Returns the one-tailed probability of the chi-squared distribution. * - * @param mixed (float) $value Value for the function - * @param mixed (int) $degrees degrees of freedom - * @param mixed $cumulative + * @param mixed $value Float value for which we want the probability + * @param mixed $degrees Integer degrees of freedom + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string */ @@ -98,8 +98,8 @@ class ChiSquared * * Returns the inverse of the right-tailed probability of the chi-squared distribution. * - * @param mixed (float) $probability Probability for the function - * @param mixed (int) $degrees degrees of freedom + * @param mixed $probability Float probability at which you want to evaluate the distribution + * @param mixed $degrees Integer degrees of freedom * * @return float|string */ @@ -134,8 +134,8 @@ class ChiSquared * * Returns the inverse of the left-tailed probability of the chi-squared distribution. * - * @param mixed (float) $probability Probability for the function - * @param mixed (int) $degrees degrees of freedom + * @param mixed $probability Float probability at which you want to evaluate the distribution + * @param mixed $degrees Integer degrees of freedom * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php index fe76816d..7cf60344 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php @@ -16,9 +16,9 @@ class Exponential * such as how long an automated bank teller takes to deliver cash. For example, you can * use EXPONDIST to determine the probability that the process takes at most 1 minute. * - * @param mixed (float) $value Value of the function - * @param mixed (float) $lambda The parameter value - * @param mixed (bool) $cumulative + * @param mixed $value Float value for which we want the probability + * @param mixed $lambda The parameter value as a float + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php index 84456873..aaf5f0df 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php @@ -17,11 +17,10 @@ class F * For example, you can examine the test scores of men and women entering high school, and determine * if the variability in the females is different from that found in the males. * - * @param mixed(float) $value Value of the function - * @param mixed(int) $u The numerator degrees of freedom - * @param mixed(int) $v The denominator degrees of freedom - * @param mixed(bool) $cumulative If cumulative is TRUE, F.DIST returns the cumulative distribution function; - * if FALSE, it returns the probability density function. + * @param mixed $value Float value for which we want the probability + * @param mixed $u The numerator degrees of freedom as an integer + * @param mixed $v The denominator degrees of freedom as an integer + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php index 1d3a7be4..fd7986b0 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php @@ -16,7 +16,7 @@ class Fisher * is normally distributed rather than skewed. Use this function to perform hypothesis * testing on the correlation coefficient. * - * @param mixed (float) $value + * @param mixed $value Float value for which we want the probability * * @return float|string */ @@ -44,20 +44,20 @@ class Fisher * analyzing correlations between ranges or arrays of data. If y = FISHER(x), then * FISHERINV(y) = x. * - * @param mixed (float) $value + * @param mixed $probability Float probability at which you want to evaluate the distribution * * @return float|string */ - public static function inverse($value) + public static function inverse($probability) { - $value = Functions::flattenSingleValue($value); + $probability = Functions::flattenSingleValue($probability); try { - self::validateFloat($value); + self::validateFloat($probability); } catch (Exception $e) { return $e->getMessage(); } - return (exp(2 * $value) - 1) / (exp(2 * $value) + 1); + return (exp(2 * $probability) - 1) / (exp(2 * $probability) + 1); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php index 2ea28391..aed25f19 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php @@ -14,7 +14,7 @@ class Gamma extends GammaBase * * Return the gamma function value. * - * @param mixed (float) $value + * @param mixed $value Float value for which we want the probability * * @return float|string The result, or a string containing an error */ @@ -40,10 +40,10 @@ class Gamma extends GammaBase * * Returns the gamma distribution. * - * @param mixed (float) $value Value at which you want to evaluate the distribution - * @param mixed (float) $a Parameter to the distribution - * @param mixed (float) $b Parameter to the distribution - * @param mixed (bool) $cumulative + * @param mixed $value Float Value at which you want to evaluate the distribution + * @param mixed $a Parameter to the distribution as a float + * @param mixed $b Parameter to the distribution as a float + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string */ @@ -74,9 +74,9 @@ class Gamma extends GammaBase * * Returns the inverse of the Gamma distribution. * - * @param mixed (float) $probability Probability at which you want to evaluate the distribution - * @param mixed (float) $alpha Parameter to the distribution - * @param mixed (float) $beta Parameter to the distribution + * @param mixed $probability Float probability at which you want to evaluate the distribution + * @param mixed $alpha Parameter to the distribution as a float + * @param mixed $beta Parameter to the distribution as a float * * @return float|string */ @@ -106,7 +106,7 @@ class Gamma extends GammaBase * * Returns the natural logarithm of the gamma function. * - * @param mixed (float) $value + * @param mixed $value Float Value at which you want to evaluate the distribution * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php index e9848ed4..487e0d46 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php @@ -16,10 +16,10 @@ class HyperGeometric * Returns the hypergeometric distribution. HYPGEOMDIST returns the probability of a given number of * sample successes, given the sample size, population successes, and population size. * - * @param mixed (int) $sampleSuccesses Number of successes in the sample - * @param mixed (int) $sampleNumber Size of the sample - * @param mixed (int) $populationSuccesses Number of successes in the population - * @param mixed (int) $populationNumber Population size + * @param mixed $sampleSuccesses Integer number of successes in the sample + * @param mixed $sampleNumber Integer size of the sample + * @param mixed $populationSuccesses Integer number of successes in the population + * @param mixed $populationNumber Integer population size * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php index 87b464fa..79d19ccf 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php @@ -15,9 +15,9 @@ class LogNormal * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed * with parameters mean and standard_dev. * - * @param mixed (float) $value - * @param mixed (float) $mean - * @param mixed (float) $stdDev + * @param mixed $value Float value for which we want the probability + * @param mixed $mean Mean value as a float + * @param mixed $stdDev Standard Deviation as a float * * @return float|string The result, or a string containing an error */ @@ -48,10 +48,10 @@ class LogNormal * Returns the lognormal distribution of x, where ln(x) is normally distributed * with parameters mean and standard_dev. * - * @param mixed (float) $value - * @param mixed (float) $mean - * @param mixed (float) $stdDev - * @param mixed (bool) $cumulative + * @param mixed $value Float value for which we want the probability + * @param mixed $mean Mean value as a float + * @param mixed $stdDev Standard Deviation as a float + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string The result, or a string containing an error */ @@ -86,11 +86,11 @@ class LogNormal /** * LOGINV. * - * Returns the inverse of the normal cumulative distribution + * Returns the inverse of the lognormal cumulative distribution * - * @param mixed (float) $probability - * @param mixed (float) $mean - * @param mixed (float) $stdDev + * @param mixed $probability Float probability for which we want the value + * @param mixed $mean Mean Value as a float + * @param mixed $stdDev Standard Deviation as a float * * @return float|string The result, or a string containing an error * diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php index b0c5552a..b24c0ecf 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php @@ -19,10 +19,10 @@ class Normal * function has a very wide range of applications in statistics, including hypothesis * testing. * - * @param mixed (float) $value - * @param mixed (float) $mean Mean Value - * @param mixed (float) $stdDev Standard Deviation - * @param mixed (bool) $cumulative + * @param mixed $value Float value for which we want the probability + * @param mixed $mean Mean value as a float + * @param mixed $stdDev Standard Deviation as a float + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string The result, or a string containing an error */ @@ -57,9 +57,9 @@ class Normal * * Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation. * - * @param mixed (float) $probability - * @param mixed (float) $mean Mean Value - * @param mixed (float) $stdDev Standard Deviation + * @param mixed $probability Float probability for which we want the value + * @param mixed $mean Mean Value as a float + * @param mixed $stdDev Standard Deviation as a float * * @return float|string The result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php index 51d097b3..e6d758e0 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php @@ -17,9 +17,9 @@ class Poisson * is predicting the number of events over a specific time, such as the number of * cars arriving at a toll plaza in 1 minute. * - * @param mixed (float) $value - * @param mixed (float) $mean Mean Value - * @param mixed (bool) $cumulative + * @param mixed $value Float value for which we want the probability + * @param mixed $mean Mean value as a float + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string The result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php index c3049f6d..0dde2006 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php @@ -15,7 +15,7 @@ class StandardNormal * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a * table of standard normal curve areas. * - * @param mixed (float) $value + * @param mixed $value Float value for which we want the probability * * @return float|string The result, or a string containing an error */ @@ -31,8 +31,8 @@ class StandardNormal * a mean of 0 (zero) and a standard deviation of one. Use this function in place of a * table of standard normal curve areas. * - * @param mixed (float) $value - * @param mixed (bool) $cumulative + * @param mixed $value Float value for which we want the probability + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string The result, or a string containing an error */ @@ -46,7 +46,7 @@ class StandardNormal * * Returns the inverse of the standard normal cumulative distribution * - * @param mixed (float) $value + * @param mixed $value Float probability for which we want the value * * @return float|string The result, or a string containing an error */ @@ -63,9 +63,10 @@ class StandardNormal * For a given hypothesized population mean, x, Z.TEST returns the probability that the sample mean would be * greater than the average of observations in the data set (array) — that is, the observed sample mean. * - * @param mixed (float) $dataSet - * @param mixed (float) $m0 Alpha Parameter - * @param mixed (null|float) $sigma Beta Parameter + * @param mixed $dataSet The dataset should be an array of float values for the observations + * @param mixed $m0 Alpha Parameter + * @param mixed $sigma A null or float value for the Beta (Standard Deviation) Parameter; + * if null, we use the standard deviation of the dataset * * @return float|string (string if result is an error) */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php index ed02fe4d..79113bad 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php @@ -16,9 +16,9 @@ class StudentT * * Returns the probability of Student's T distribution. * - * @param mixed (float) $value Value for the function - * @param mixed (float) $degrees degrees of freedom - * @param mixed (int) $tails number of tails (1 or 2) + * @param mixed $value Float value for the distribution + * @param mixed $degrees Integer value for degrees of freedom + * @param mixed $tails Integer value for the number of tails (1 or 2) * * @return float|string The result, or a string containing an error */ @@ -48,8 +48,8 @@ class StudentT * * Returns the one-tailed probability of the chi-squared distribution. * - * @param mixed (float) $probability Probability for the function - * @param mixed (float) $degrees degrees of freedom + * @param mixed $probability Float probability for the function + * @param mixed $degrees Integer value for degrees of freedom * * @return float|string The result, or a string containing an error */ @@ -79,7 +79,7 @@ class StudentT } /** - * @return float|int + * @return float */ private static function calculateDistribution(float $value, int $degrees, int $tails) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php index 2064c2e2..5c28e69a 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php @@ -15,10 +15,10 @@ class Weibull * Returns the Weibull distribution. Use this distribution in reliability * analysis, such as calculating a device's mean time to failure. * - * @param mixed (float) $value - * @param mixed (float) $alpha Alpha Parameter - * @param mixed (float) $beta Beta Parameter - * @param mixed (bool) $cumulative + * @param mixed $value Float value for the distribution + * @param mixed $alpha Float alpha Parameter + * @param mixed $beta Float beta Parameter + * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false) * * @return float|string (string if result is an error) */ diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php b/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php index 0001b7bf..1f454247 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php @@ -69,9 +69,9 @@ class Percentiles * rather than floored (as MS Excel), so value 3 for a value set of 1, 2, 3, 4 will return * 0.667 rather than 0.666 * - * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers - * @param mixed (int) $value the number whose rank you want to find - * @param mixed (int) $significance the number of significant digits for the returned percentage value + * @param mixed $valueSet An array of (float) values, or a reference to, a list of numbers + * @param mixed $value The number whose rank you want to find + * @param mixed $significance The (integer) number of significant digits for the returned percentage value * * @return float|string (string if result is an error) */ @@ -151,11 +151,11 @@ class Percentiles * * Returns the rank of a number in a list of numbers. * - * @param mixed (float) $value the number whose rank you want to find - * @param mixed (float[]) $valueSet An array of, or a reference to, a list of numbers - * @param mixed (int) $order Order to sort the values in the value set + * @param mixed $value The number whose rank you want to find + * @param mixed $valueSet An array of float values, or a reference to, a list of numbers + * @param mixed $order Order to sort the values in the value set * - * @return float|string The result, or a string containing an error + * @return float|string The result, or a string containing an error (0 = Descending, 1 = Ascending) */ public static function RANK($value, $valueSet, $order = self::RANK_SORT_DESCENDING) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php index 84cdfea1..c381d718 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -19,8 +19,8 @@ class Permutations * combinations, for which the internal order is not significant. Use this function * for lottery-style probability calculations. * - * @param mixed (int) $numObjs Number of different objects - * @param mixed (int) $numInSet Number of objects in each permutation + * @param mixed $numObjs Integer number of different objects + * @param mixed $numInSet Integer number of objects in each permutation * * @return int|string Number of permutations, or a string containing an error */ @@ -40,7 +40,7 @@ class Permutations return Functions::NAN(); } - return round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)); + return (int) round(MathTrig\Fact::funcFact($numObjs) / MathTrig\Fact::funcFact($numObjs - $numInSet)); } /** @@ -49,8 +49,8 @@ class Permutations * Returns the number of permutations for a given number of objects (with repetitions) * that can be selected from the total objects. * - * @param int $numObjs Number of different objects - * @param int $numInSet Number of objects in each permutation + * @param mixed $numObjs Integer number of different objects + * @param mixed $numInSet Integer number of objects in each permutation * * @return int|string Number of permutations, or a string containing an error */ @@ -70,6 +70,6 @@ class Permutations return Functions::NAN(); } - return $numObjs ** $numInSet; + return (int) ($numObjs ** $numInSet); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index 8c88c54c..e745d1b7 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -109,7 +109,7 @@ class Trends * Calculates, or predicts, a future value by using existing values. * The predicted value is a y-value for a given x-value. * - * @param mixed (float) $xValue Value of X for which we want to find Y + * @param mixed $xValue Float value of X for which we want to find Y * @param mixed $yValues array of mixed Data Series Y * @param mixed $xValues of mixed Data Series X * @@ -140,7 +140,7 @@ class Trends * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @param mixed[] $newValues Values of X for which we want to find Y - * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 + * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not * * @return array of float */ @@ -196,8 +196,8 @@ class Trends * * @param mixed[] $yValues Data Series Y * @param null|mixed[] $xValues Data Series X - * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 - * @param mixed (bool) $stats a logical value specifying whether to return additional regression statistics + * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not + * @param mixed $stats A logical (boolean) value specifying whether to return additional regression statistics * * @return array|int|string The result, or a string containing an error */ @@ -257,8 +257,8 @@ class Trends * * @param mixed[] $yValues Data Series Y * @param null|mixed[] $xValues Data Series X - * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 - * @param mixed (bool) $stats a logical value specifying whether to return additional regression statistics + * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not + * @param mixed $stats A logical (boolean) value specifying whether to return additional regression statistics * * @return array|int|string The result, or a string containing an error */ @@ -397,7 +397,7 @@ class Trends * @param mixed[] $yValues Data Series Y * @param mixed[] $xValues Data Series X * @param mixed[] $newValues Values of X for which we want to find Y - * @param mixed (bool) $const a logical value specifying whether to force the intersect to equal 0 + * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not * * @return array of float */ diff --git a/src/PhpSpreadsheet/Calculation/TextData.php b/src/PhpSpreadsheet/Calculation/TextData.php index c7e91a47..0bde3b7f 100644 --- a/src/PhpSpreadsheet/Calculation/TextData.php +++ b/src/PhpSpreadsheet/Calculation/TextData.php @@ -399,8 +399,8 @@ class TextData * * @see Use the exact() method in the TextData\Text class instead * - * @param $value1 - * @param $value2 + * @param mixed $value1 + * @param mixed $value2 * * @return bool */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php index 846a3124..36b5efbd 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php +++ b/src/PhpSpreadsheet/Calculation/TextData/CaseConvert.php @@ -13,7 +13,7 @@ class CaseConvert * * Converts a string value to upper case. * - * @param mixed (string) $mixedCaseValue + * @param mixed $mixedCaseValue The string value to convert to lower case */ public static function lower($mixedCaseValue): string { @@ -31,7 +31,7 @@ class CaseConvert * * Converts a string value to upper case. * - * @param mixed (string) $mixedCaseValue + * @param mixed $mixedCaseValue The string value to convert to upper case */ public static function upper($mixedCaseValue): string { @@ -47,9 +47,9 @@ class CaseConvert /** * PROPERCASE. * - * Converts a string value to upper case. + * Converts a string value to proper or title case. * - * @param mixed (string) $mixedCaseValue + * @param mixed $mixedCaseValue The string value to convert to title case */ public static function proper($mixedCaseValue): string { diff --git a/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php b/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php index 0003e0cd..4397b538 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php +++ b/src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php @@ -10,7 +10,7 @@ class CharacterConvert /** * CHARACTER. * - * @param mixed (int) $character Value + * @param mixed $character Integer Value to convert to its character representation */ public static function character($character): string { @@ -31,7 +31,7 @@ class CharacterConvert /** * ASCIICODE. * - * @param mixed (string) $characters Value + * @param mixed $characters String character to convert to its ASCII value * * @return int|string A string if arguments are invalid */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/Extract.php b/src/PhpSpreadsheet/Calculation/TextData/Extract.php index 7ef76546..2f994858 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Extract.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Extract.php @@ -10,8 +10,8 @@ class Extract /** * LEFT. * - * @param mixed (string) $value Value - * @param mixed (int) $chars Number of characters + * @param mixed $value String value from which to extract characters + * @param mixed $chars The number of characters to extract (as an integer) */ public static function left($value = '', $chars = 1): string { @@ -32,9 +32,9 @@ class Extract /** * MID. * - * @param mixed (string) $value Value - * @param mixed (int) $start Start character - * @param mixed (int) $chars Number of characters + * @param mixed $value String value from which to extract characters + * @param mixed $start Integer offset of the first character that we want to extract + * @param mixed $chars The number of characters to extract (as an integer) */ public static function mid($value = '', $start = 1, $chars = null): string { @@ -56,8 +56,8 @@ class Extract /** * RIGHT. * - * @param mixed (string) $value Value - * @param mixed (int) $chars Number of characters + * @param mixed $value String value from which to extract characters + * @param mixed $chars The number of characters to extract (as an integer) */ public static function right($value = '', $chars = 1): string { diff --git a/src/PhpSpreadsheet/Calculation/TextData/Format.php b/src/PhpSpreadsheet/Calculation/TextData/Format.php index c061818e..5c76454f 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Format.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Format.php @@ -18,10 +18,10 @@ class Format * This function converts a number to text using currency format, with the decimals rounded to the specified place. * The format used is $#,##0.00_);($#,##0.00).. * - * @param mixed (float) $value The value to format - * @param mixed (int) $decimals The number of digits to display to the right of the decimal point. - * If decimals is negative, number is rounded to the left of the decimal point. - * If you omit decimals, it is assumed to be 2 + * @param mixed $value The value to format + * @param mixed $decimals The number of digits to display to the right of the decimal point (as an integer). + * If decimals is negative, number is rounded to the left of the decimal point. + * If you omit decimals, it is assumed to be 2 */ public static function DOLLAR($value = 0, $decimals = 2): string { @@ -52,9 +52,9 @@ class Format /** * FIXEDFORMAT. * - * @param mixed $value Value to check - * @param mixed $decimals - * @param mixed (bool) $noCommas + * @param mixed $value The value to format + * @param mixed $decimals Integer value for the number of decimal places that should be formatted + * @param mixed $noCommas Boolean value indicating whether the value should have thousands separators or not */ public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false): string { @@ -87,8 +87,8 @@ class Format /** * TEXTFORMAT. * - * @param mixed $value Value to check - * @param mixed (string) $format Format mask to use + * @param mixed $value The value to format + * @param mixed $format A string with the Format mask that should be used */ public static function TEXTFORMAT($value, $format): string { @@ -151,9 +151,9 @@ class Format /** * NUMBERVALUE. * - * @param mixed $value Value to check - * @param mixed (string) $decimalSeparator decimal separator, defaults to locale defined value - * @param mixed (string) $groupSeparator group/thosands separator, defaults to locale defined value + * @param mixed $value The value to format + * @param mixed $decimalSeparator A string with the decimal separator to use, defaults to locale defined value + * @param mixed $groupSeparator A string with the group/thousands separator to use, defaults to locale defined value * * @return float|string */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/Replace.php b/src/PhpSpreadsheet/Calculation/TextData/Replace.php index a1975d6b..7ca710ef 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Replace.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Replace.php @@ -9,10 +9,10 @@ class Replace /** * REPLACE. * - * @param mixed (string) $oldText String to modify - * @param mixed (int) $start Start character - * @param mixed (int) $chars Number of characters - * @param mixed (string) $newText String to replace in defined position + * @param mixed $oldText The text string value to modify + * @param mixed $start Integer offset for start character of the replacement + * @param mixed $chars Integer number of characters to replace from the start offset + * @param mixed $newText String to replace in the defined position */ public static function replace($oldText, $start, $chars, $newText): string { @@ -30,10 +30,10 @@ class Replace /** * SUBSTITUTE. * - * @param mixed (string) $text Value - * @param mixed (string) $fromText From Value - * @param mixed (string) $toText To Value - * @param mixed (int) $instance Instance Number + * @param mixed $text The text string value to modify + * @param mixed $fromText The string value that we want to replace in $text + * @param mixed $toText The string value that we want to replace with in $text + * @param mixed $instance Integer instance Number for the occurrence of frmText to change */ public static function substitute($text = '', $fromText = '', $toText = '', $instance = 0): string { diff --git a/src/PhpSpreadsheet/Calculation/TextData/Search.php b/src/PhpSpreadsheet/Calculation/TextData/Search.php index cf1bf241..2da688d8 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Search.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Search.php @@ -11,9 +11,9 @@ class Search /** * SEARCHSENSITIVE. * - * @param mixed (string) $needle The string to look for - * @param mixed (string) $haystack The string in which to look - * @param mixed (int) $offset Offset within $haystack + * @param mixed $needle The string to look for + * @param mixed $haystack The string in which to look + * @param mixed $offset Integer offset within $haystack to start searching from * * @return int|string */ @@ -46,9 +46,9 @@ class Search /** * SEARCHINSENSITIVE. * - * @param mixed (string) $needle The string to look for - * @param mixed (string) $haystack The string in which to look - * @param mixed (int) $offset Offset within $haystack + * @param mixed $needle The string to look for + * @param mixed $haystack The string in which to look + * @param mixed $offset Integer offset within $haystack to start searching from * * @return int|string */ diff --git a/src/PhpSpreadsheet/Calculation/TextData/Text.php b/src/PhpSpreadsheet/Calculation/TextData/Text.php index 338cdd20..6e408891 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Text.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Text.php @@ -10,7 +10,7 @@ class Text /** * STRINGLENGTH. * - * @param mixed (string) $value Value + * @param mixed $value String Value */ public static function length($value = ''): int { @@ -28,8 +28,8 @@ class Text * EXACT is case-sensitive but ignores formatting differences. * Use EXACT to test text being entered into a document. * - * @param mixed (string) $value1 - * @param mixed (string) $value2 + * @param mixed $value1 String Value + * @param mixed $value2 String Value */ public static function exact($value1, $value2): bool { diff --git a/src/PhpSpreadsheet/Calculation/TextData/Trim.php b/src/PhpSpreadsheet/Calculation/TextData/Trim.php index 01fff1a8..b5d66455 100644 --- a/src/PhpSpreadsheet/Calculation/TextData/Trim.php +++ b/src/PhpSpreadsheet/Calculation/TextData/Trim.php @@ -12,7 +12,7 @@ class Trim /** * TRIMNONPRINTABLE. * - * @param mixed (string) $stringValue Value to check + * @param mixed $stringValue String Value to check * * @return null|string */ @@ -38,7 +38,7 @@ class Trim /** * TRIMSPACES. * - * @param mixed (string) $stringValue Value to check + * @param mixed $stringValue String Value to check * * @return null|string */ diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php index 337501f9..f1f0bea2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php @@ -319,8 +319,8 @@ class CalculationTest extends TestCase } /** - * @param $expectedResult - * @param $dataArray + * @param mixed $expectedResult + * @param mixed $dataArray * @param string $formula * @param string $cellCoordinates where to put the formula * @param string[] $shouldBeSetInCacheCells coordinates of cells that must diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php index f144c6f2..eceb0519 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php @@ -10,7 +10,7 @@ class TimeValueTest extends AllSetupTeardown * @dataProvider providerTIMEVALUE * * @param mixed $expectedResult - * @param $timeValue + * @param mixed $timeValue */ public function testTIMEVALUE($expectedResult, $timeValue): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php index c1602eda..cf3a39d4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php @@ -17,8 +17,8 @@ class IfErrorTest extends TestCase * @dataProvider providerIFERROR * * @param mixed $expectedResult - * @param $value - * @param $return + * @param mixed $value + * @param mixed $return */ public function testIFERROR($expectedResult, $value, $return): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php index 2976761a..63302276 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php @@ -17,8 +17,8 @@ class IfNaTest extends TestCase * @dataProvider providerIFNA * * @param mixed $expectedResult - * @param $value - * @param $return + * @param mixed $value + * @param mixed $return */ public function testIFNA($expectedResult, $value, $return): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php index c8cc8645..56839f7f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php @@ -8,7 +8,7 @@ class EvenTest extends AllSetupTeardown * @dataProvider providerEVEN * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testEVEN($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php index f3627205..83fe898c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php @@ -8,7 +8,7 @@ class FactDoubleTest extends AllSetupTeardown * @dataProvider providerFACTDOUBLE * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testFACTDOUBLE($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php index c599a30e..21740ef3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php @@ -8,7 +8,7 @@ class OddTest extends AllSetupTeardown * @dataProvider providerODD * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testODD($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php index dff5370d..0ec90e78 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php @@ -8,7 +8,7 @@ class SignTest extends AllSetupTeardown * @dataProvider providerSIGN * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testSIGN($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php index bb4bba4b..c49934ea 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php @@ -17,7 +17,7 @@ class SqrtPiTest extends TestCase * @dataProvider providerSQRTPI * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testSQRTPI($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php index efd212c8..2c3e592c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php @@ -17,7 +17,7 @@ class FisherInvTest extends TestCase * @dataProvider providerFISHERINV * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testFISHERINV($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php index 788ffc6a..7705517a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php @@ -17,7 +17,7 @@ class FisherTest extends TestCase * @dataProvider providerFISHER * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testFISHER($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php index d0ae623f..31407feb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php @@ -17,7 +17,7 @@ class GammaLnTest extends TestCase * @dataProvider providerGAMMALN * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testGAMMALN($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php index cf22df02..324f5054 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php @@ -11,7 +11,7 @@ class CharTest extends TestCase * @dataProvider providerCHAR * * @param mixed $expectedResult - * @param $character + * @param mixed $character */ public function testCHAR($expectedResult, $character): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php index 31dcc5e6..ddc27a5d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php @@ -11,7 +11,7 @@ class CleanTest extends TestCase * @dataProvider providerCLEAN * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testCLEAN($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php index 9c19f347..7bf5a00f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php @@ -11,7 +11,7 @@ class CodeTest extends TestCase * @dataProvider providerCODE * * @param mixed $expectedResult - * @param $character + * @param mixed $character */ public function testCODE($expectedResult, $character): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php index 080a9ac3..450643f7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php @@ -33,7 +33,7 @@ class LeftTest extends TestCase * @dataProvider providerLocaleLEFT * * @param string $expectedResult - * @param $value + * @param mixed $value * @param mixed $locale * @param mixed $characters */ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php index bca2b389..c6ffc43d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php @@ -11,7 +11,7 @@ class LenTest extends TestCase * @dataProvider providerLEN * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testLEN($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php index 085dd79f..f90ab378 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php @@ -17,7 +17,7 @@ class LowerTest extends TestCase * @dataProvider providerLOWER * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testLOWER($expectedResult, $value): void { @@ -34,7 +34,7 @@ class LowerTest extends TestCase * @dataProvider providerLocaleLOWER * * @param string $expectedResult - * @param $value + * @param mixed $value * @param mixed $locale */ public function testLowerWithLocaleBoolean($expectedResult, $locale, $value): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php index 0d0678f2..c9859969 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php @@ -33,7 +33,7 @@ class MidTest extends TestCase * @dataProvider providerLocaleMID * * @param string $expectedResult - * @param $value + * @param mixed $value * @param mixed $locale * @param mixed $offset * @param mixed $characters diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php index 48359721..58096c5e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php @@ -17,7 +17,7 @@ class ProperTest extends TestCase * @dataProvider providerPROPER * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testPROPER($expectedResult, $value): void { @@ -34,7 +34,7 @@ class ProperTest extends TestCase * @dataProvider providerLocaleLOWER * * @param string $expectedResult - * @param $value + * @param mixed $value * @param mixed $locale */ public function testLowerWithLocaleBoolean($expectedResult, $locale, $value): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php index da4c7491..26ccc549 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php @@ -33,7 +33,7 @@ class RightTest extends TestCase * @dataProvider providerLocaleRIGHT * * @param string $expectedResult - * @param $value + * @param mixed $value * @param mixed $locale * @param mixed $characters */ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php index c7606c05..e2f5cd01 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php @@ -11,7 +11,7 @@ class TTest extends TestCase * @dataProvider providerT * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testT($expectedResult, $value): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php index 91890ded..6b2dbc7a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php @@ -11,7 +11,7 @@ class TrimTest extends TestCase * @dataProvider providerTRIM * * @param mixed $expectedResult - * @param $character + * @param mixed $character */ public function testTRIM($expectedResult, $character): void { diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php index cf2d569d..352aa5b7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php @@ -17,7 +17,7 @@ class UpperTest extends TestCase * @dataProvider providerUPPER * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testUPPER($expectedResult, $value): void { @@ -34,7 +34,7 @@ class UpperTest extends TestCase * @dataProvider providerLocaleLOWER * * @param string $expectedResult - * @param $value + * @param mixed $value * @param mixed $locale */ public function testLowerWithLocaleBoolean($expectedResult, $locale, $value): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php index 355193de..607c926b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php @@ -32,7 +32,7 @@ class ValueTest extends TestCase * @dataProvider providerVALUE * * @param mixed $expectedResult - * @param $value + * @param mixed $value */ public function testVALUE($expectedResult, $value): void { From 6446039f4fce67ae851c8c6c3961357308c64f92 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sat, 3 Apr 2021 22:37:18 +0200 Subject: [PATCH 154/187] PHPStan stuff (#1984) --- .../Calculation/Calculation.php | 30 ++++++++++--------- src/PhpSpreadsheet/Style/Alignment.php | 3 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 0aa2a6da..1699b5a0 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -130,7 +130,7 @@ class Calculation /** * Error message for any error that was raised/thrown by the calculation engine. * - * @var string + * @var null|string */ public $formulaError; @@ -204,7 +204,7 @@ class Calculation /** * Locale-specific translations for Excel constants (True, False and Null). * - * @var string[] + * @var array */ public static $localeBoolean = [ 'TRUE' => 'TRUE', @@ -216,7 +216,7 @@ class Calculation * Excel constant string translations to their PHP equivalents * Constant conversion from text name/value to actual (datatyped) value. * - * @var string[] + * @var array */ private static $excelConstants = [ 'TRUE' => true, @@ -3457,8 +3457,8 @@ class Calculation /** * Ensure that paired matrix operands are both matrices and of the same size. * - * @param mixed &$operand1 First matrix operand - * @param mixed &$operand2 Second matrix operand + * @param mixed $operand1 First matrix operand + * @param mixed $operand2 Second matrix operand * @param int $resize Flag indicating whether the matrices should be resized to match * and (if so), whether the smaller dimension should grow or the * larger should shrink. @@ -3502,7 +3502,7 @@ class Calculation /** * Read the dimensions of a matrix, and re-index it with straight numeric keys starting from row 0, column 0. * - * @param array &$matrix matrix operand + * @param array $matrix matrix operand * * @return int[] An array comprising the number of rows, and number of columns */ @@ -3527,8 +3527,8 @@ class Calculation /** * Ensure that paired matrix operands are both matrices of the same size. * - * @param mixed &$matrix1 First matrix operand - * @param mixed &$matrix2 Second matrix operand + * @param mixed $matrix1 First matrix operand + * @param mixed $matrix2 Second matrix operand * @param int $matrix1Rows Row size of first matrix operand * @param int $matrix1Columns Column size of first matrix operand * @param int $matrix2Rows Row size of second matrix operand @@ -3570,8 +3570,8 @@ class Calculation /** * Ensure that paired matrix operands are both matrices of the same size. * - * @param mixed &$matrix1 First matrix operand - * @param mixed &$matrix2 Second matrix operand + * @param mixed $matrix1 First matrix operand + * @param mixed $matrix2 Second matrix operand * @param int $matrix1Rows Row size of first matrix operand * @param int $matrix1Columns Column size of first matrix operand * @param int $matrix2Rows Row size of second matrix operand @@ -3688,6 +3688,8 @@ class Calculation return $typeString . ' with a value of ' . $this->showValue($value); } + + return null; } /** @@ -3782,7 +3784,7 @@ class Calculation /** * @param string $formula * - * @return bool + * @return array|false */ private function internalParseFormula($formula, ?Cell $pCell = null) { @@ -4254,7 +4256,7 @@ class Calculation * @param mixed $tokens * @param null|string $cellID * - * @return bool + * @return array|false */ private function processTokenStack($tokens, $cellID = null, ?Cell $pCell = null) { @@ -5101,7 +5103,7 @@ class Calculation /** * Extract range values. * - * @param string &$pRange String based range representation + * @param string $pRange String based range representation * @param Worksheet $pSheet Worksheet * @param bool $resetLog Flag indicating whether calculation log should be reset or not * @@ -5154,7 +5156,7 @@ class Calculation /** * Extract range values. * - * @param string &$pRange String based range representation + * @param string $pRange String based range representation * @param Worksheet $pSheet Worksheet * @param bool $resetLog Flag indicating whether calculation log should be reset or not * diff --git a/src/PhpSpreadsheet/Style/Alignment.php b/src/PhpSpreadsheet/Style/Alignment.php index 04a089fe..226a5427 100644 --- a/src/PhpSpreadsheet/Style/Alignment.php +++ b/src/PhpSpreadsheet/Style/Alignment.php @@ -392,7 +392,8 @@ class Alignment extends Supervisor if ( $this->getHorizontal() != self::HORIZONTAL_GENERAL && $this->getHorizontal() != self::HORIZONTAL_LEFT && - $this->getHorizontal() != self::HORIZONTAL_RIGHT + $this->getHorizontal() != self::HORIZONTAL_RIGHT && + $this->getHorizontal() != self::HORIZONTAL_DISTRIBUTED ) { $pValue = 0; // indent not supported } From 42761f90b7b3ecd5e319cf330129a8b588abb2b5 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 4 Apr 2021 14:44:06 +0200 Subject: [PATCH 155/187] Financial start refactoring cash flow functions (#1986) * Start extracting CashFlow functions from Financial, beginning with the simple Single Rate flows * Extracting Variable Periodic and NonPeriodic CashFlow functions from Financial * Some more unit tests for exception cases --- src/PhpSpreadsheet/Calculation/Financial.php | 355 +++--------------- .../Calculation/Financial/CashFlow/Single.php | 104 +++++ .../CashFlow/Variable/NonPeriodic.php | 233 ++++++++++++ .../Financial/CashFlow/Variable/Periodic.php | 160 ++++++++ .../data/Calculation/Financial/FVSCHEDULE.php | 18 + tests/data/Calculation/Financial/IRR.php | 35 +- tests/data/Calculation/Financial/MIRR.php | 32 +- tests/data/Calculation/Financial/NPV.php | 8 +- .../data/Calculation/Financial/PDURATION.php | 36 +- tests/data/Calculation/Financial/RRI.php | 36 +- 10 files changed, 680 insertions(+), 337 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index 984d31bf..fde1d3da 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -756,21 +756,19 @@ class Financial * Excel Function: * FVSCHEDULE(principal,schedule) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Single::futureValue() + * Use the futureValue() method in the Financial\CashFlow\Single class instead + * * @param float $principal the present value * @param float[] $schedule an array of interest rates to apply * - * @return float + * @return float|string */ public static function FVSCHEDULE($principal, $schedule) { - $principal = Functions::flattenSingleValue($principal); - $schedule = Functions::flattenArray($schedule); - - foreach ($schedule as $rate) { - $principal *= 1 + $rate; - } - - return $principal; + return Financial\CashFlow\Single::futureValue($principal, $schedule); } /** @@ -876,6 +874,8 @@ class Financial * Excel Function: * IRR(values[,guess]) * + * @Deprecated 1.18.0 + * * @param mixed $values An array or a reference to cells that contain numbers for which you want * to calculate the internal rate of return. * Values must contain at least one positive value and one negative value to @@ -883,56 +883,13 @@ class Financial * @param mixed $guess A number that you guess is close to the result of IRR * * @return float|string + * + *@see Financial\CashFlow\Variable\Periodic::rate() + * Use the IRR() method in the Financial\CashFlow\Variable\Periodic class instead */ public static function IRR($values, $guess = 0.1) { - if (!is_array($values)) { - return Functions::VALUE(); - } - $values = Functions::flattenArray($values); - $guess = Functions::flattenSingleValue($guess); - - // create an initial range, with a root somewhere between 0 and guess - $x1 = 0.0; - $x2 = $guess; - $f1 = self::NPV($x1, $values); - $f2 = self::NPV($x2, $values); - for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) { - if (($f1 * $f2) < 0.0) { - break; - } - if (abs($f1) < abs($f2)) { - $f1 = self::NPV($x1 += 1.6 * ($x1 - $x2), $values); - } else { - $f2 = self::NPV($x2 += 1.6 * ($x2 - $x1), $values); - } - } - if (($f1 * $f2) > 0.0) { - return Functions::VALUE(); - } - - $f = self::NPV($x1, $values); - if ($f < 0.0) { - $rtb = $x1; - $dx = $x2 - $x1; - } else { - $rtb = $x2; - $dx = $x1 - $x2; - } - - for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) { - $dx *= 0.5; - $x_mid = $rtb + $dx; - $f_mid = self::NPV($x_mid, $values); - if ($f_mid <= 0.0) { - $rtb = $x_mid; - } - if ((abs($f_mid) < self::FINANCIAL_PRECISION) || (abs($dx) < self::FINANCIAL_PRECISION)) { - return $x_mid; - } - } - - return Functions::VALUE(); + return Financial\CashFlow\Variable\Periodic::rate($values, $guess); } /** @@ -986,6 +943,11 @@ class Financial * Excel Function: * MIRR(values,finance_rate, reinvestment_rate) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Variable\Periodic::modifiedRate() + * Use the MIRR() method in the Financial\CashFlow\Variable\Periodic class instead + * * @param mixed $values An array or a reference to cells that contain a series of payments and * income occurring at regular intervals. * Payments are negative value, income is positive values. @@ -996,34 +958,7 @@ class Financial */ public static function MIRR($values, $finance_rate, $reinvestment_rate) { - if (!is_array($values)) { - return Functions::VALUE(); - } - $values = Functions::flattenArray($values); - $finance_rate = Functions::flattenSingleValue($finance_rate); - $reinvestment_rate = Functions::flattenSingleValue($reinvestment_rate); - $n = count($values); - - $rr = 1.0 + $reinvestment_rate; - $fr = 1.0 + $finance_rate; - - $npv_pos = $npv_neg = 0.0; - foreach ($values as $i => $v) { - if ($v >= 0) { - $npv_pos += $v / $rr ** $i; - } else { - $npv_neg += $v / $fr ** $i; - } - } - - if (($npv_neg == 0) || ($npv_pos == 0) || ($reinvestment_rate <= -1)) { - return Functions::VALUE(); - } - - $mirr = ((-$npv_pos * $rr ** $n) - / ($npv_neg * ($rr))) ** (1.0 / ($n - 1)) - 1.0; - - return is_finite($mirr) ? $mirr : Functions::VALUE(); + return Financial\CashFlow\Variable\Periodic::modifiedRate($values, $finance_rate, $reinvestment_rate); } /** @@ -1094,28 +1029,16 @@ class Financial * * Returns the Net Present Value of a cash flow series given a discount rate. * + * @Deprecated 1.18.0 + * * @return float + * + *@see Financial\CashFlow\Variable\Periodic::presentValue() + * Use the NPV() method in the Financial\CashFlow\Variable\Periodic class instead */ public static function NPV(...$args) { - // Return value - $returnValue = 0; - - // Loop through arguments - $aArgs = Functions::flattenArray($args); - - // Calculate - $rate = array_shift($aArgs); - $countArgs = count($aArgs); - for ($i = 1; $i <= $countArgs; ++$i) { - // Is it a numeric value? - if (is_numeric($aArgs[$i - 1])) { - $returnValue += $aArgs[$i - 1] / (1 + $rate) ** $i; - } - } - - // Return - return $returnValue; + return Financial\CashFlow\Variable\Periodic::presentValue(...$args); } /** @@ -1123,6 +1046,11 @@ class Financial * * Calculates the number of periods required for an investment to reach a specified value. * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Single::periods() + * Use the periods() method in the Financial\CashFlow\Single class instead + * * @param float $rate Interest rate per period * @param float $pv Present Value * @param float $fv Future Value @@ -1131,18 +1059,7 @@ class Financial */ public static function PDURATION($rate = 0, $pv = 0, $fv = 0) { - $rate = Functions::flattenSingleValue($rate); - $pv = Functions::flattenSingleValue($pv); - $fv = Functions::flattenSingleValue($fv); - - // Validate parameters - if (!is_numeric($rate) || !is_numeric($pv) || !is_numeric($fv)) { - return Functions::VALUE(); - } elseif ($rate <= 0.0 || $pv <= 0.0 || $fv <= 0.0) { - return Functions::NAN(); - } - - return (log($fv) - log($pv)) / log(1 + $rate); + return Financial\CashFlow\Single::periods($rate, $pv, $fv); } /** @@ -1470,6 +1387,11 @@ class Financial * * Calculates the interest rate required for an investment to grow to a specified future value . * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Single::interestRate() + * Use the interestRate() method in the Financial\CashFlow\Single class instead + * * @param float $nper The number of periods over which the investment is made * @param float $pv Present Value * @param float $fv Future Value @@ -1478,18 +1400,7 @@ class Financial */ public static function RRI($nper = 0, $pv = 0, $fv = 0) { - $nper = Functions::flattenSingleValue($nper); - $pv = Functions::flattenSingleValue($pv); - $fv = Functions::flattenSingleValue($fv); - - // Validate parameters - if (!is_numeric($nper) || !is_numeric($pv) || !is_numeric($fv)) { - return Functions::VALUE(); - } elseif ($nper <= 0.0 || $pv <= 0.0 || $fv < 0.0) { - return Functions::NAN(); - } - - return ($fv / $pv) ** (1 / $nper) - 1; + return Financial\CashFlow\Single::interestRate($nper, $pv, $fv); } /** @@ -1601,85 +1512,6 @@ class Financial return TreasuryBill::yield($settlement, $maturity, $price); } - private static function bothNegAndPos($neg, $pos) - { - return $neg && $pos; - } - - private static function xirrPart2(&$values) - { - $valCount = count($values); - $foundpos = false; - $foundneg = false; - for ($i = 0; $i < $valCount; ++$i) { - $fld = $values[$i]; - if (!is_numeric($fld)) { - return Functions::VALUE(); - } elseif ($fld > 0) { - $foundpos = true; - } elseif ($fld < 0) { - $foundneg = true; - } - } - if (!self::bothNegAndPos($foundneg, $foundpos)) { - return Functions::NAN(); - } - - return ''; - } - - private static function xirrPart1(&$values, &$dates) - { - if ((!is_array($values)) && (!is_array($dates))) { - return Functions::NA(); - } - $values = Functions::flattenArray($values); - $dates = Functions::flattenArray($dates); - if (count($values) != count($dates)) { - return Functions::NAN(); - } - - $datesCount = count($dates); - for ($i = 0; $i < $datesCount; ++$i) { - try { - $dates[$i] = DateTimeExcel\Helpers::getDateValue($dates[$i]); - } catch (Exception $e) { - return $e->getMessage(); - } - } - - return self::xirrPart2($values); - } - - private static function xirrPart3($values, $dates, $x1, $x2) - { - $f = self::xnpvOrdered($x1, $values, $dates, false); - if ($f < 0.0) { - $rtb = $x1; - $dx = $x2 - $x1; - } else { - $rtb = $x2; - $dx = $x1 - $x2; - } - - $rslt = Functions::VALUE(); - for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) { - $dx *= 0.5; - $x_mid = $rtb + $dx; - $f_mid = self::xnpvOrdered($x_mid, $values, $dates, false); - if ($f_mid <= 0.0) { - $rtb = $x_mid; - } - if ((abs($f_mid) < self::FINANCIAL_PRECISION) || (abs($dx) < self::FINANCIAL_PRECISION)) { - $rslt = $x_mid; - - break; - } - } - - return $rslt; - } - /** * XIRR. * @@ -1688,6 +1520,11 @@ class Financial * Excel Function: * =XIRR(values,dates,guess) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Variable\NonPeriodic::rate() + * Use the rate() method in the Financial\CashFlow\Variable\NonPeriodic class instead + * * @param float[] $values A series of cash flow payments * The series of values must contain at least one positive value & one negative value * @param mixed[] $dates A series of payment dates @@ -1699,37 +1536,7 @@ class Financial */ public static function XIRR($values, $dates, $guess = 0.1) { - $rslt = self::xirrPart1($values, $dates); - if ($rslt) { - return $rslt; - } - - // create an initial range, with a root somewhere between 0 and guess - $guess = Functions::flattenSingleValue($guess); - $x1 = 0.0; - $x2 = $guess ?: 0.1; - $f1 = self::xnpvOrdered($x1, $values, $dates, false); - $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 (($f1 * $f2) < 0.0) { - $found = true; - - break; - } elseif (abs($f1) < abs($f2)) { - $f1 = self::xnpvOrdered($x1 += 1.6 * ($x1 - $x2), $values, $dates, false); - } else { - $f2 = self::xnpvOrdered($x2 += 1.6 * ($x2 - $x1), $values, $dates, false); - } - } - if (!$found) { - return Functions::NAN(); - } - - return self::xirrPart3($values, $dates, $x1, $x2); + return Financial\CashFlow\Variable\NonPeriodic::rate($values, $dates, $guess); } /** @@ -1741,6 +1548,11 @@ class Financial * Excel Function: * =XNPV(rate,values,dates) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Variable\NonPeriodic::presentValue() + * Use the presentValue() method in the Financial\CashFlow\Variable\NonPeriodic class instead + * * @param float $rate the discount rate to apply to the cash flows * @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates. * The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. @@ -1754,68 +1566,7 @@ class Financial */ public static function XNPV($rate, $values, $dates) { - return self::xnpvOrdered($rate, $values, $dates, true); - } - - private static function validateXnpv($rate, $values, $dates) - { - if (!is_numeric($rate)) { - return Functions::VALUE(); - } - $valCount = count($values); - if ($valCount != count($dates)) { - return Functions::NAN(); - } - if ($valCount > 1 && ((min($values) > 0) || (max($values) < 0))) { - return Functions::NAN(); - } - $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); - if (is_string($date0)) { - return Functions::VALUE(); - } - - return ''; - } - - private static function xnpvOrdered($rate, $values, $dates, $ordered = true) - { - $rate = Functions::flattenSingleValue($rate); - $values = Functions::flattenArray($values); - $dates = Functions::flattenArray($dates); - $valCount = count($values); - - try { - $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); - } catch (Exception $e) { - return $e->getMessage(); - } - $rslt = self::validateXnpv($rate, $values, $dates); - if ($rslt) { - return $rslt; - } - $xnpv = 0.0; - for ($i = 0; $i < $valCount; ++$i) { - if (!is_numeric($values[$i])) { - return Functions::VALUE(); - } - - try { - $datei = DateTimeExcel\Helpers::getDateValue($dates[$i]); - } catch (Exception $e) { - return $e->getMessage(); - } - if ($date0 > $datei) { - $dif = $ordered ? Functions::NAN() : -DateTimeExcel\DateDif::funcDateDif($datei, $date0, 'd'); - } else { - $dif = DateTimeExcel\DateDif::funcDateDif($date0, $datei, 'd'); - } - if (!is_numeric($dif)) { - return $dif; - } - $xnpv += $values[$i] / (1 + $rate) ** ($dif / 365); - } - - return is_finite($xnpv) ? $xnpv : Functions::VALUE(); + return Financial\CashFlow\Variable\NonPeriodic::presentValue($rate, $values, $dates); } /** @@ -1823,7 +1574,10 @@ class Financial * * Returns the annual yield of a security that pays interest at maturity. * - * @see Use the yieldDiscounted() method in the Financial\Securities\Yields class instead + * @Deprecated 1.18.0 + * + * @see Financial\Securities\Yields::yieldDiscounted() + * Use the yieldDiscounted() method in the Financial\Securities\Yields class instead * * @param mixed $settlement The security's settlement date. * The security's settlement date is the date after the issue date when the security @@ -1853,7 +1607,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the yieldAtMaturity() method in the Financial\Securities\Yields class instead + * @see Financial\Securities\Yields::yieldAtMaturity() + * Use the yieldAtMaturity() method in the Financial\Securities\Yields class instead * * @param mixed $settlement The security's settlement date. * The security's settlement date is the date after the issue date when the security diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php index 3f1c8bc6..9fecd755 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php @@ -2,6 +2,110 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow; +use PhpOffice\PhpSpreadsheet\Calculation\Exception; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\BaseValidations; +use PhpOffice\PhpSpreadsheet\Calculation\Functions; + class Single { + use BaseValidations; + + /** + * FVSCHEDULE. + * + * Returns the future value of an initial principal after applying a series of compound interest rates. + * Use FVSCHEDULE to calculate the future value of an investment with a variable or adjustable rate. + * + * Excel Function: + * FVSCHEDULE(principal,schedule) + * + * @param mixed $principal the present value + * @param float[] $schedule an array of interest rates to apply + * + * @return float|string + */ + public static function futureValue($principal, $schedule) + { + $principal = Functions::flattenSingleValue($principal); + $schedule = Functions::flattenArray($schedule); + + try { + $principal = self::validateFloat($principal); + + foreach ($schedule as $rate) { + $rate = self::validateFloat($rate); + $principal *= 1 + $rate; + } + } catch (Exception $e) { + return $e->getMessage(); + } + + return $principal; + } + + /** + * PDURATION. + * + * Calculates the number of periods required for an investment to reach a specified value. + * + * @param float $rate Interest rate per period + * @param float $presentValue Present Value + * @param float $futureValue Future Value + * + * @return float|string Result, or a string containing an error + */ + public static function periods($rate = 0.0, $presentValue = 0.0, $futureValue = 0.0) + { + $rate = Functions::flattenSingleValue($rate); + $presentValue = Functions::flattenSingleValue($presentValue); + $futureValue = Functions::flattenSingleValue($futureValue); + + try { + $rate = self::validateFloat($rate); + $presentValue = self::validateFloat($presentValue); + $futureValue = self::validateFloat($futureValue); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Validate parameters + if ($rate <= 0.0 || $presentValue <= 0.0 || $futureValue <= 0.0) { + return Functions::NAN(); + } + + return (log($futureValue) - log($presentValue)) / log(1 + $rate); + } + + /** + * RRI. + * + * Calculates the interest rate required for an investment to grow to a specified future value . + * + * @param float $periods The number of periods over which the investment is made + * @param float $presentValue Present Value + * @param float $futureValue Future Value + * + * @return float|string Result, or a string containing an error + */ + public static function interestRate($periods = 0.0, $presentValue = 0.0, $futureValue = 0.0) + { + $periods = Functions::flattenSingleValue($periods); + $presentValue = Functions::flattenSingleValue($presentValue); + $futureValue = Functions::flattenSingleValue($futureValue); + + try { + $periods = self::validateFloat($periods); + $presentValue = self::validateFloat($presentValue); + $futureValue = self::validateFloat($futureValue); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Validate parameters + if ($periods <= 0.0 || $presentValue <= 0.0 || $futureValue < 0.0) { + return Functions::NAN(); + } + + return ($futureValue / $presentValue) ** (1 / $periods) - 1; + } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php new file mode 100644 index 00000000..d78015e6 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php @@ -0,0 +1,233 @@ +getMessage(); + } + } + + return self::xirrPart2($values); + } + + private static function xirrPart2(&$values) + { + $valCount = count($values); + $foundpos = false; + $foundneg = false; + for ($i = 0; $i < $valCount; ++$i) { + $fld = $values[$i]; + if (!is_numeric($fld)) { + return Functions::VALUE(); + } elseif ($fld > 0) { + $foundpos = true; + } elseif ($fld < 0) { + $foundneg = true; + } + } + if (!self::bothNegAndPos($foundneg, $foundpos)) { + return Functions::NAN(); + } + + return ''; + } + + private static function xirrPart3($values, $dates, $x1, $x2) + { + $f = self::xnpvOrdered($x1, $values, $dates, false); + if ($f < 0.0) { + $rtb = $x1; + $dx = $x2 - $x1; + } else { + $rtb = $x2; + $dx = $x1 - $x2; + } + + $rslt = Functions::VALUE(); + for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) { + $dx *= 0.5; + $x_mid = $rtb + $dx; + $f_mid = self::xnpvOrdered($x_mid, $values, $dates, false); + if ($f_mid <= 0.0) { + $rtb = $x_mid; + } + if ((abs($f_mid) < self::FINANCIAL_PRECISION) || (abs($dx) < self::FINANCIAL_PRECISION)) { + $rslt = $x_mid; + + break; + } + } + + return $rslt; + } + + private static function xnpvOrdered($rate, $values, $dates, $ordered = true) + { + $rate = Functions::flattenSingleValue($rate); + $values = Functions::flattenArray($values); + $dates = Functions::flattenArray($dates); + $valCount = count($values); + + try { + $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); + } catch (Exception $e) { + return $e->getMessage(); + } + $rslt = self::validateXnpv($rate, $values, $dates); + if ($rslt) { + return $rslt; + } + $xnpv = 0.0; + for ($i = 0; $i < $valCount; ++$i) { + if (!is_numeric($values[$i])) { + return Functions::VALUE(); + } + + try { + $datei = DateTimeExcel\Helpers::getDateValue($dates[$i]); + } catch (Exception $e) { + return $e->getMessage(); + } + if ($date0 > $datei) { + $dif = $ordered ? Functions::NAN() : -DateTimeExcel\DateDif::funcDateDif($datei, $date0, 'd'); + } else { + $dif = DateTimeExcel\DateDif::funcDateDif($date0, $datei, 'd'); + } + if (!is_numeric($dif)) { + return $dif; + } + $xnpv += $values[$i] / (1 + $rate) ** ($dif / 365); + } + + return is_finite($xnpv) ? $xnpv : Functions::VALUE(); + } + + private static function validateXnpv($rate, $values, $dates) + { + if (!is_numeric($rate)) { + return Functions::VALUE(); + } + $valCount = count($values); + if ($valCount != count($dates)) { + return Functions::NAN(); + } + if ($valCount > 1 && ((min($values) > 0) || (max($values) < 0))) { + return Functions::NAN(); + } + $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); + if (is_string($date0)) { + return Functions::VALUE(); + } + + return ''; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php new file mode 100644 index 00000000..c42df0c3 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php @@ -0,0 +1,160 @@ + 0.0) { + return Functions::VALUE(); + } + + $f = self::presentValue($x1, $values); + if ($f < 0.0) { + $rtb = $x1; + $dx = $x2 - $x1; + } else { + $rtb = $x2; + $dx = $x1 - $x2; + } + + for ($i = 0; $i < self::FINANCIAL_MAX_ITERATIONS; ++$i) { + $dx *= 0.5; + $x_mid = $rtb + $dx; + $f_mid = self::presentValue($x_mid, $values); + if ($f_mid <= 0.0) { + $rtb = $x_mid; + } + if ((abs($f_mid) < self::FINANCIAL_PRECISION) || (abs($dx) < self::FINANCIAL_PRECISION)) { + return $x_mid; + } + } + + return Functions::VALUE(); + } + + /** + * MIRR. + * + * Returns the modified internal rate of return for a series of periodic cash flows. MIRR considers both + * the cost of the investment and the interest received on reinvestment of cash. + * + * Excel Function: + * MIRR(values,finance_rate, reinvestment_rate) + * + * @param mixed $values An array or a reference to cells that contain a series of payments and + * income occurring at regular intervals. + * Payments are negative value, income is positive values. + * @param mixed $financeRate The interest rate you pay on the money used in the cash flows + * @param mixed $reinvestmentRate The interest rate you receive on the cash flows as you reinvest them + * + * @return float|string Result, or a string containing an error + */ + public static function modifiedRate($values, $financeRate, $reinvestmentRate) + { + if (!is_array($values)) { + return Functions::VALUE(); + } + $values = Functions::flattenArray($values); + $financeRate = Functions::flattenSingleValue($financeRate); + $reinvestmentRate = Functions::flattenSingleValue($reinvestmentRate); + $n = count($values); + + $rr = 1.0 + $reinvestmentRate; + $fr = 1.0 + $financeRate; + + $npvPos = $npvNeg = 0.0; + foreach ($values as $i => $v) { + if ($v >= 0) { + $npvPos += $v / $rr ** $i; + } else { + $npvNeg += $v / $fr ** $i; + } + } + + if (($npvNeg === 0.0) || ($npvPos === 0.0) || ($reinvestmentRate <= -1.0)) { + return Functions::VALUE(); + } + + $mirr = ((-$npvPos * $rr ** $n) + / ($npvNeg * ($rr))) ** (1.0 / ($n - 1)) - 1.0; + + return is_finite($mirr) ? $mirr : Functions::VALUE(); + } + + /** + * NPV. + * + * Returns the Net Present Value of a cash flow series given a discount rate. + * + * @param mixed $rate + * + * @return float + */ + public static function presentValue($rate, ...$args) + { + $returnValue = 0; + + $rate = Functions::flattenSingleValue($rate); + $aArgs = Functions::flattenArray($args); + + // Calculate + $countArgs = count($aArgs); + for ($i = 1; $i <= $countArgs; ++$i) { + // Is it a numeric value? + if (is_numeric($aArgs[$i - 1])) { + $returnValue += $aArgs[$i - 1] / (1 + $rate) ** $i; + } + } + + return $returnValue; + } +} diff --git a/tests/data/Calculation/Financial/FVSCHEDULE.php b/tests/data/Calculation/Financial/FVSCHEDULE.php index b332912c..975fca60 100644 --- a/tests/data/Calculation/Financial/FVSCHEDULE.php +++ b/tests/data/Calculation/Financial/FVSCHEDULE.php @@ -36,4 +36,22 @@ return [ ], ], ], + [ + '#VALUE!', + 'NaN', + [ + 0.089999999999999997, + 0.11, + 0.10000000000000001, + ], + ], + [ + '#VALUE!', + 100, + [ + 0.089999999999999997, + 'NaN', + 0.10000000000000001, + ], + ], ]; diff --git a/tests/data/Calculation/Financial/IRR.php b/tests/data/Calculation/Financial/IRR.php index 142ab204..f6c24c13 100644 --- a/tests/data/Calculation/Financial/IRR.php +++ b/tests/data/Calculation/Financial/IRR.php @@ -32,7 +32,7 @@ return [ 15000, 18000, ], - 0.10000000000000001, + 0.10, ], [ -0.13618951095869, @@ -41,7 +41,7 @@ return [ [ 20, 24, - 28.800000000000001, + 28.8, ], ], ], @@ -52,10 +52,35 @@ return [ [ 20, 24, - 28.800000000000001, - 34.560000000000002, - 41.469999999999999, + 28.8, + 34.56, + 41.47, ], ], ], + [ + '#VALUE!', + 999, + 1.23, + ], + [ + '#VALUE!', + [ + 70000, + 12000, + 15000, + 18000, + 21000, + ], + ], + [ + '#VALUE!', + [ + -70000, + -12000, + -15000, + -18000, + -21000, + ], + ], ]; diff --git a/tests/data/Calculation/Financial/MIRR.php b/tests/data/Calculation/Financial/MIRR.php index b32edcbe..9bd6e209 100644 --- a/tests/data/Calculation/Financial/MIRR.php +++ b/tests/data/Calculation/Financial/MIRR.php @@ -15,7 +15,7 @@ return [ 46000, ], ], - 0.10000000000000001, + 0.10, 0.12, ], [ @@ -28,7 +28,7 @@ return [ 21000, ], ], - 0.10000000000000001, + 0.10, 0.12, ], [ @@ -43,8 +43,8 @@ return [ 46000, ], ], - 0.10000000000000001, - 0.14000000000000001, + 0.10, + 0.14, ], [ 0.74021752686287001, @@ -74,4 +74,28 @@ return [ 5.5, 5, ], + [ + '#VALUE!', + 999, + 1.23, + 2.34, + ], + [ + '#VALUE!', + [0.12, 0.13, 0.125], + 1.23, + 2.34, + ], + [ + '#VALUE!', + [-0.12, -0.13, -0.125], + 1.23, + 2.34, + ], + [ + '#VALUE!', + [-0.12, 0.13, 0.125], + 1.23, + -2.34, + ], ]; diff --git a/tests/data/Calculation/Financial/NPV.php b/tests/data/Calculation/Financial/NPV.php index 27db7f4d..ac854269 100644 --- a/tests/data/Calculation/Financial/NPV.php +++ b/tests/data/Calculation/Financial/NPV.php @@ -5,7 +5,7 @@ return [ [ 1188.4434123352, - 0.10000000000000001, + 0.10, -10000, 3000, 4200, @@ -13,7 +13,7 @@ return [ ], [ 41922.061554931999, - 0.080000000000000002, + 0.08, 8000, 9200, 10000, @@ -22,7 +22,7 @@ return [ ], [ 36250.534912984003, - 0.080000000000000002, + 0.08, 8000, 9200, 10000, @@ -32,7 +32,7 @@ return [ ], [ 12678.677633095, - 0.050000000000000003, + 0.05, 2000, 2400, 2900, diff --git a/tests/data/Calculation/Financial/PDURATION.php b/tests/data/Calculation/Financial/PDURATION.php index cfb6080f..1886f26d 100644 --- a/tests/data/Calculation/Financial/PDURATION.php +++ b/tests/data/Calculation/Financial/PDURATION.php @@ -1,18 +1,6 @@ Date: Sat, 3 Apr 2021 17:42:11 +0900 Subject: [PATCH 156/187] PHPStan Level 2 --- .php_cs.dist | 2 +- phpstan.neon.dist | 7 +- src/PhpSpreadsheet/Calculation/DateTime.php | 2 +- .../Calculation/DateTimeExcel/DateDif.php | 2 +- .../Calculation/DateTimeExcel/DateValue.php | 2 +- .../Calculation/DateTimeExcel/Days360.php | 24 +- .../Calculation/DateTimeExcel/WeekNum.php | 4 +- .../Calculation/DateTimeExcel/WorkDay.php | 2 + .../Calculation/Engineering/BesselI.php | 8 +- .../Calculation/Engineering/BesselJ.php | 6 +- .../Calculation/Engineering/BesselK.php | 4 +- .../CashFlow/Variable/NonPeriodic.php | 1 + src/PhpSpreadsheet/Calculation/Functions.php | 4 +- .../Calculation/LookupRef/Matrix.php | 2 +- src/PhpSpreadsheet/Cell/AddressHelper.php | 4 +- src/PhpSpreadsheet/Cell/Coordinate.php | 19 +- src/PhpSpreadsheet/Chart/Axis.php | 6 +- src/PhpSpreadsheet/Chart/Chart.php | 2 +- src/PhpSpreadsheet/Chart/GridLines.php | 2 +- src/PhpSpreadsheet/Chart/PlotArea.php | 4 +- src/PhpSpreadsheet/Document/Properties.php | 6 +- src/PhpSpreadsheet/HashTable.php | 19 +- src/PhpSpreadsheet/Reader/Gnumeric.php | 4 +- src/PhpSpreadsheet/Reader/Html.php | 2 - src/PhpSpreadsheet/Reader/Ods.php | 11 +- src/PhpSpreadsheet/Reader/Slk.php | 6 +- src/PhpSpreadsheet/Reader/Xls.php | 11 +- src/PhpSpreadsheet/Reader/Xls/MD5.php | 27 +- src/PhpSpreadsheet/Reader/Xlsx.php | 20 +- src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 6 +- src/PhpSpreadsheet/Reader/Xml.php | 13 +- src/PhpSpreadsheet/ReferenceHelper.php | 43 ++- src/PhpSpreadsheet/RichText/ITextElement.php | 2 +- src/PhpSpreadsheet/RichText/TextElement.php | 2 +- src/PhpSpreadsheet/Shared/Date.php | 4 +- src/PhpSpreadsheet/Shared/Font.php | 54 ++-- .../Shared/JAMA/CholeskyDecomposition.php | 4 +- src/PhpSpreadsheet/Shared/JAMA/Matrix.php | 11 - .../Shared/JAMA/QRDecomposition.php | 78 +++-- .../JAMA/SingularValueDecomposition.php | 2 +- .../Shared/OLE/ChainedBlockStream.php | 2 +- src/PhpSpreadsheet/Shared/OLE/PPS.php | 2 +- src/PhpSpreadsheet/Shared/OLE/PPS/Root.php | 4 +- src/PhpSpreadsheet/Shared/OLERead.php | 4 +- src/PhpSpreadsheet/Shared/StringHelper.php | 2 +- src/PhpSpreadsheet/Shared/Trend/Trend.php | 2 +- src/PhpSpreadsheet/Shared/Xls.php | 3 +- src/PhpSpreadsheet/Style/Border.php | 12 +- src/PhpSpreadsheet/Style/Color.php | 19 +- .../ConditionalFormatValueObject.php | 2 - .../ConditionalFormattingRuleExtension.php | 2 - src/PhpSpreadsheet/Style/Style.php | 47 ++- src/PhpSpreadsheet/Worksheet/AutoFilter.php | 2 +- src/PhpSpreadsheet/Worksheet/Worksheet.php | 14 +- src/PhpSpreadsheet/Writer/Html.php | 14 +- src/PhpSpreadsheet/Writer/Ods.php | 113 +++++-- src/PhpSpreadsheet/Writer/Ods/Content.php | 2 +- src/PhpSpreadsheet/Writer/Ods/Meta.php | 9 +- src/PhpSpreadsheet/Writer/Ods/MetaInf.php | 2 +- src/PhpSpreadsheet/Writer/Ods/Mimetype.php | 6 +- .../Writer/Ods/NamedExpressions.php | 4 +- src/PhpSpreadsheet/Writer/Ods/Settings.php | 7 +- src/PhpSpreadsheet/Writer/Ods/Styles.php | 5 +- src/PhpSpreadsheet/Writer/Ods/Thumbnails.php | 6 +- src/PhpSpreadsheet/Writer/Ods/WriterPart.php | 2 + src/PhpSpreadsheet/Writer/Xls.php | 13 +- src/PhpSpreadsheet/Writer/Xls/Escher.php | 8 +- src/PhpSpreadsheet/Writer/Xls/Parser.php | 24 +- src/PhpSpreadsheet/Writer/Xls/Workbook.php | 13 +- src/PhpSpreadsheet/Writer/Xls/Worksheet.php | 108 ++----- src/PhpSpreadsheet/Writer/Xlsx.php | 289 ++++++++++++------ src/PhpSpreadsheet/Writer/Xlsx/Chart.php | 8 +- src/PhpSpreadsheet/Writer/Xlsx/Comments.php | 5 +- src/PhpSpreadsheet/Writer/Xlsx/Drawing.php | 17 +- src/PhpSpreadsheet/Writer/Xlsx/Rels.php | 4 +- src/PhpSpreadsheet/Writer/Xlsx/Theme.php | 14 +- src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php | 4 +- .../Cell/AdvancedValueBinderTest.php | 3 - .../Cell/CoordinateTest.php | 14 + .../Cell/DefaultValueBinderTest.php | 3 +- tests/PhpSpreadsheetTests/DefinedNameTest.php | 1 + .../Functional/ColumnWidthTest.php | 2 - .../Functional/CommentsTest.php | 2 - .../Reader/CsvContiguousTest.php | 8 +- .../Reader/Security/XmlScannerTest.php | 2 - tests/PhpSpreadsheetTests/Reader/XlsxTest.php | 1 - .../Reader/Xml/XmlTest.php | 2 - tests/PhpSpreadsheetTests/SpreadsheetTest.php | 3 - tests/data/Cell/IndexesFromString.php | 74 +++++ tests/data/CellCoordinates.php | 28 ++ 90 files changed, 778 insertions(+), 591 deletions(-) create mode 100644 tests/data/Cell/IndexesFromString.php diff --git a/.php_cs.dist b/.php_cs.dist index f8797e88..1a646420 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -160,7 +160,7 @@ return PhpCsFixer\Config::create() 'php_unit_test_annotation' => true, 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], 'php_unit_test_class_requires_covers' => false, // We don't care as much as we should about coverage - 'phpdoc_add_missing_param_annotation' => true, + 'phpdoc_add_missing_param_annotation' => false, // Don't add things that bring no value 'phpdoc_align' => false, // Waste of time 'phpdoc_annotation_without_dot' => true, 'phpdoc_indent' => true, diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 476513dc..53bbb0e6 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,11 +1,16 @@ parameters: - level: 1 + level: 2 paths: - src/ - tests/ ignoreErrors: - '~^Class GdImage not found\.$~' + - '~^Return typehint of method .* has invalid type GdImage\.$~' + - '~^Property .* has unknown class GdImage as its type\.$~' + - '~^Parameter .* of method .* has invalid typehint type GdImage\.$~' # Ignore all JpGraph issues - '~^Constant (MARK_CIRCLE|MARK_CROSS|MARK_DIAMOND|MARK_DTRIANGLE|MARK_FILLEDCIRCLE|MARK_SQUARE|MARK_STAR|MARK_UTRIANGLE|MARK_X|SIDE_RIGHT) not found\.$~' - '~^Instantiated class (AccBarPlot|AccLinePlot|BarPlot|ContourPlot|Graph|GroupBarPlot|GroupBarPlot|LinePlot|LinePlot|PieGraph|PiePlot|PiePlot3D|PiePlotC|RadarGraph|RadarPlot|ScatterPlot|Spline|StockPlot) not found\.$~' + - '~^Call to method .*\(\) on an unknown class (AccBarPlot|AccLinePlot|BarPlot|ContourPlot|Graph|GroupBarPlot|GroupBarPlot|LinePlot|LinePlot|PieGraph|PiePlot|PiePlot3D|PiePlotC|RadarGraph|RadarPlot|ScatterPlot|Spline|StockPlot)\.$~' + - '~^Access to property .* on an unknown class (AccBarPlot|AccLinePlot|BarPlot|ContourPlot|Graph|GroupBarPlot|GroupBarPlot|LinePlot|LinePlot|PieGraph|PiePlot|PiePlot3D|PiePlotC|RadarGraph|RadarPlot|ScatterPlot|Spline|StockPlot)\.$~' diff --git a/src/PhpSpreadsheet/Calculation/DateTime.php b/src/PhpSpreadsheet/Calculation/DateTime.php index e3580cde..3b79a6d6 100644 --- a/src/PhpSpreadsheet/Calculation/DateTime.php +++ b/src/PhpSpreadsheet/Calculation/DateTime.php @@ -198,7 +198,7 @@ class DateTime * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag */ - public static function DATEVALUE($dateValue = 1) + public static function DATEVALUE($dateValue) { return DateTimeExcel\DateValue::funcDateValue($dateValue); } diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php index ace22cbf..c0d1fa4b 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateDif.php @@ -89,7 +89,7 @@ class DateDif private static function datedifM(DateInterval $PHPDiffDateObject): int { - return (int) 12 * $PHPDiffDateObject->format('%y') + $PHPDiffDateObject->format('%m'); + return 12 * (int) $PHPDiffDateObject->format('%y') + (int) $PHPDiffDateObject->format('%m'); } private static function datedifMD(int $startDays, int $endDays, DateTime $PHPEndDateObject, DateInterval $PHPDiffDateObject): int diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php index 3c15d06a..86b8d3d9 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php @@ -33,7 +33,7 @@ class DateValue * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag */ - public static function funcDateValue($dateValue = 1) + public static function funcDateValue($dateValue) { $dti = new DateTimeImmutable(); $baseYear = Date::getExcelCalendar(); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php index 18a1abc8..47de02c3 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Days360.php @@ -19,20 +19,20 @@ class Days360 * DAYS360(startDate,endDate[,method]) * * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer), - * PHP DateTime object, or a standard date string + * PHP DateTime object, or a standard date string * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer), - * PHP DateTime object, or a standard date string + * PHP DateTime object, or a standard date string * @param mixed $method US or European Method as a bool - * FALSE or omitted: U.S. (NASD) method. If the starting date is - * the last day of a month, it becomes equal to the 30th of the - * same month. If the ending date is the last day of a month and - * the starting date is earlier than the 30th of a month, the - * ending date becomes equal to the 1st of the next month; - * otherwise the ending date becomes equal to the 30th of the - * same month. - * TRUE: European method. Starting dates and ending dates that - * occur on the 31st of a month become equal to the 30th of the - * same month. + * FALSE or omitted: U.S. (NASD) method. If the starting date is + * the last day of a month, it becomes equal to the 30th of the + * same month. If the ending date is the last day of a month and + * the starting date is earlier than the 30th of a month, the + * ending date becomes equal to the 1st of the next month; + * otherwise the ending date becomes equal to the 30th of the + * same month. + * TRUE: European method. Starting dates and ending dates that + * occur on the 31st of a month become equal to the 30th of the + * same month. * * @return int|string Number of days between start date and end date */ diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php index 1dd15edb..9b2de4d0 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekNum.php @@ -67,9 +67,9 @@ class WeekNum return 0; } Helpers::silly1900($PHPDateObject, '+ 5 years'); // 1905 calendar matches - $dayOfYear = $PHPDateObject->format('z'); + $dayOfYear = (int) $PHPDateObject->format('z'); $PHPDateObject->modify('-' . $dayOfYear . ' days'); - $firstDayOfFirstWeek = $PHPDateObject->format('w'); + $firstDayOfFirstWeek = (int) $PHPDateObject->format('w'); $daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7; $daysInFirstWeek += 7 * !$daysInFirstWeek; $endFirstWeek = $daysInFirstWeek - 1; diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php index f812624e..09816d33 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php @@ -129,6 +129,7 @@ class WorkDay $startDoW = WeekDay::funcWeekDay($startDate, 3); if (WeekDay::funcWeekDay($startDate, 3) >= 5) { + // @phpstan-ignore-next-line $startDate += -$startDoW + 4; ++$endDays; } @@ -173,6 +174,7 @@ class WorkDay // Adjust the calculated end date if it falls over a weekend $endDoW = WeekDay::funcWeekDay($endDate, 3); if ($endDoW >= 5) { + // @phpstan-ignore-next-line $endDate += -$endDoW + 4; } } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php index 89977101..bbb24bd4 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php @@ -22,11 +22,11 @@ class BesselI * This code provides a more accurate calculation * * @param mixed $x A float value at which to evaluate the function. - * If x is nonnumeric, BESSELI returns the #VALUE! error value. + * If x is nonnumeric, BESSELI returns the #VALUE! error value. * @param mixed $ord The integer order of the Bessel function. - * If ord is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELI returns the #VALUE! error value. - * If $ord < 0, BESSELI returns the #NUM! error value. + * If ord is not an integer, it is truncated. + * If $ord is nonnumeric, BESSELI returns the #VALUE! error value. + * If $ord < 0, BESSELI returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php index e16c1519..730e2870 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php @@ -21,11 +21,11 @@ class BesselJ * values with x < -8 and x > 8. This code provides a more accurate calculation * * @param mixed $x A float value at which to evaluate the function. - * If x is nonnumeric, BESSELJ returns the #VALUE! error value. + * If x is nonnumeric, BESSELJ returns the #VALUE! error value. * @param mixed $ord The integer order of the Bessel function. * If ord is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value. - * If $ord < 0, BESSELJ returns the #NUM! error value. + * If $ord is nonnumeric, BESSELJ returns the #VALUE! error value. + * If $ord < 0, BESSELJ returns the #NUM! error value. * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php index 57794e03..18a2ac5c 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php @@ -19,10 +19,10 @@ class BesselK * BESSELK(x,ord) * * @param mixed $x A float value at which to evaluate the function. - * If x is nonnumeric, BESSELK returns the #VALUE! error value. + * If x is nonnumeric, BESSELK returns the #VALUE! error value. * @param mixed $ord The integer order of the Bessel function. * If ord is not an integer, it is truncated. - * If $ord is nonnumeric, BESSELK returns the #VALUE! error value. + * If $ord is nonnumeric, BESSELK returns the #VALUE! error value. * If $ord < 0, BESSELKI returns the #NUM! error value. * * @return float|string Result, or a string containing an error diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php index d78015e6..58f8fdaf 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php @@ -198,6 +198,7 @@ class NonPeriodic return $e->getMessage(); } if ($date0 > $datei) { + /** @phpstan-ignore-next-line */ $dif = $ordered ? Functions::NAN() : -DateTimeExcel\DateDif::funcDateDif($datei, $date0, 'd'); } else { $dif = DateTimeExcel\DateDif::funcDateDif($date0, $datei, 'd'); diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index 6ad387e8..34ebefed 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -576,7 +576,7 @@ class Functions /** * Convert a multi-dimensional array to a simple 1-dimensional array. * - * @param mixed (array) $array Array to be flattened + * @param array|mixed $array Array to be flattened * * @return array Flattened array */ @@ -609,7 +609,7 @@ class Functions /** * Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing. * - * @param mixed (array) $array Array to be flattened + * @param array|mixed $array Array to be flattened * * @return array Flattened array */ diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php index 59af4258..5b666608 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php @@ -9,7 +9,7 @@ class Matrix /** * TRANSPOSE. * - * @param mixed (array) $matrixData A matrix of values + * @param array|mixed $matrixData A matrix of values * * @return array */ diff --git a/src/PhpSpreadsheet/Cell/AddressHelper.php b/src/PhpSpreadsheet/Cell/AddressHelper.php index 04fa3b8c..b0e34e25 100644 --- a/src/PhpSpreadsheet/Cell/AddressHelper.php +++ b/src/PhpSpreadsheet/Cell/AddressHelper.php @@ -27,7 +27,7 @@ class AddressHelper } // Bracketed R references are relative to the current row if ($rowReference[0] === '[') { - $rowReference = $currentRowNumber + trim($rowReference, '[]'); + $rowReference = $currentRowNumber + (int) trim($rowReference, '[]'); } $columnReference = $cellReference[4]; // Empty C reference is the current column @@ -36,7 +36,7 @@ class AddressHelper } // Bracketed C references are relative to the current column if (is_string($columnReference) && $columnReference[0] === '[') { - $columnReference = $currentColumnNumber + trim($columnReference, '[]'); + $columnReference = $currentColumnNumber + (int) trim($columnReference, '[]'); } if ($columnReference <= 0 || $rowReference <= 0) { diff --git a/src/PhpSpreadsheet/Cell/Coordinate.php b/src/PhpSpreadsheet/Cell/Coordinate.php index 8d81f3a1..0b3917f2 100644 --- a/src/PhpSpreadsheet/Cell/Coordinate.php +++ b/src/PhpSpreadsheet/Cell/Coordinate.php @@ -25,7 +25,7 @@ abstract class Coordinate * * @param string $pCoordinateString eg: 'A1' * - * @return string[] Array containing column and row (indexes 0 and 1) + * @return array{0: string, 1: string} Array containing column and row (indexes 0 and 1) */ public static function coordinateFromString($pCoordinateString) { @@ -40,6 +40,23 @@ abstract class Coordinate throw new Exception('Invalid cell coordinate ' . $pCoordinateString); } + /** + * Get indexes from a string coordinates. + * + * @param string $coordinates eg: 'A1', '$B$12' + * + * @return array{0: int, 1: int} Array containing column index and row index (indexes 0 and 1) + */ + public static function indexesFromString(string $coordinates): array + { + [$col, $row] = self::coordinateFromString($coordinates); + + return [ + self::columnIndexFromString(ltrim($col, '$')), + (int) ltrim($row, '$'), + ]; + } + /** * Checks if a coordinate represents a range of cells. * diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php index 455a5faa..6a2e2df5 100644 --- a/src/PhpSpreadsheet/Chart/Axis.php +++ b/src/PhpSpreadsheet/Chart/Axis.php @@ -135,10 +135,8 @@ class Axis extends Properties * Get Series Data Type. * * @param mixed $format_code - * - * @return string */ - public function setAxisNumberProperties($format_code) + public function setAxisNumberProperties($format_code): void { $this->axisNumber['format'] = (string) $format_code; $this->axisNumber['source_linked'] = 0; @@ -367,7 +365,7 @@ class Axis extends Properties /** * Set Shadow Properties from Mapped Values. * - * @param mixed &$reference + * @param mixed $reference * * @return $this */ diff --git a/src/PhpSpreadsheet/Chart/Chart.php b/src/PhpSpreadsheet/Chart/Chart.php index 20eb2aee..4fdff6ff 100644 --- a/src/PhpSpreadsheet/Chart/Chart.php +++ b/src/PhpSpreadsheet/Chart/Chart.php @@ -424,7 +424,7 @@ class Chart /** * Get the top left position of the chart. * - * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell + * @return array{cell: string, xOffset: int, yOffset: int} an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell */ public function getTopLeftPosition() { diff --git a/src/PhpSpreadsheet/Chart/GridLines.php b/src/PhpSpreadsheet/Chart/GridLines.php index 385b278b..c388f2c9 100644 --- a/src/PhpSpreadsheet/Chart/GridLines.php +++ b/src/PhpSpreadsheet/Chart/GridLines.php @@ -318,7 +318,7 @@ class GridLines extends Properties /** * Set Shadow Properties Values. * - * @param mixed &$reference + * @param mixed $reference * * @return $this */ diff --git a/src/PhpSpreadsheet/Chart/PlotArea.php b/src/PhpSpreadsheet/Chart/PlotArea.php index 954777cf..fbd01184 100644 --- a/src/PhpSpreadsheet/Chart/PlotArea.php +++ b/src/PhpSpreadsheet/Chart/PlotArea.php @@ -43,10 +43,8 @@ class PlotArea /** * Get Number of Plot Groups. - * - * @return array of DataSeries */ - public function getPlotGroupCount() + public function getPlotGroupCount(): int { return count($this->plotSeries); } diff --git a/src/PhpSpreadsheet/Document/Properties.php b/src/PhpSpreadsheet/Document/Properties.php index 951d334d..911d53ce 100644 --- a/src/PhpSpreadsheet/Document/Properties.php +++ b/src/PhpSpreadsheet/Document/Properties.php @@ -392,13 +392,11 @@ class Properties /** * Get a Custom Property Type. * - * @return string + * @return null|string */ public function getCustomPropertyType(string $propertyName) { - if (isset($this->customProperties[$propertyName])) { - return $this->customProperties[$propertyName]['type']; - } + return $this->customProperties[$propertyName]['type'] ?? null; } private function identifyPropertyType($propertyValue) diff --git a/src/PhpSpreadsheet/HashTable.php b/src/PhpSpreadsheet/HashTable.php index 90ea806b..0823236c 100644 --- a/src/PhpSpreadsheet/HashTable.php +++ b/src/PhpSpreadsheet/HashTable.php @@ -2,12 +2,15 @@ namespace PhpOffice\PhpSpreadsheet; +/** + * @template T of IComparable + */ class HashTable { /** * HashTable elements. * - * @var IComparable[] + * @var T[] */ protected $items = []; @@ -21,7 +24,7 @@ class HashTable /** * Create a new \PhpOffice\PhpSpreadsheet\HashTable. * - * @param IComparable[] $pSource Optional source array to create HashTable from + * @param T[] $pSource Optional source array to create HashTable from */ public function __construct($pSource = null) { @@ -34,7 +37,7 @@ class HashTable /** * Add HashTable items from source. * - * @param IComparable[] $pSource Source array to create HashTable from + * @param T[] $pSource Source array to create HashTable from */ public function addFromSource(?array $pSource = null): void { @@ -51,7 +54,7 @@ class HashTable /** * Add HashTable item. * - * @param IComparable $pSource Item to add + * @param T $pSource Item to add */ public function add(IComparable $pSource): void { @@ -65,7 +68,7 @@ class HashTable /** * Remove HashTable item. * - * @param IComparable $pSource Item to remove + * @param T $pSource Item to remove */ public function remove(IComparable $pSource): void { @@ -123,7 +126,7 @@ class HashTable * * @param int $pIndex * - * @return IComparable + * @return T */ public function getByIndex($pIndex) { @@ -139,7 +142,7 @@ class HashTable * * @param string $pHashCode * - * @return IComparable + * @return T */ public function getByHashCode($pHashCode) { @@ -153,7 +156,7 @@ class HashTable /** * HashTable to array. * - * @return IComparable[] + * @return T[] */ public function toArray() { diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index 2bec2a13..dfba56d7 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -657,7 +657,7 @@ class Gnumeric extends BaseReader $column = $columnAttributes['No']; $columnWidth = ((float) $columnAttributes['Unit']) / 5.4; $hidden = (isset($columnAttributes['Hidden'])) && ((string) $columnAttributes['Hidden'] == '1'); - $columnCount = $columnAttributes['Count'] ?? 1; + $columnCount = (int) ($columnAttributes['Count'] ?? 1); while ($c < $column) { $this->spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($defaultWidth); ++$c; @@ -696,7 +696,7 @@ class Gnumeric extends BaseReader $row = $rowAttributes['No']; $rowHeight = (float) $rowAttributes['Unit']; $hidden = (isset($rowAttributes['Hidden'])) && ((string) $rowAttributes['Hidden'] == '1'); - $rowCount = $rowAttributes['Count'] ?? 1; + $rowCount = (int) ($rowAttributes['Count'] ?? 1); while ($r < $row) { ++$r; $this->spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight); diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index 09148d9f..f235f9b1 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -910,8 +910,6 @@ class Html extends BaseReader /** * Check if has #, so we can get clean hex. * - * @param $value - * * @return null|string */ public function getStyleColor($value) diff --git a/src/PhpSpreadsheet/Reader/Ods.php b/src/PhpSpreadsheet/Reader/Ods.php index 59d934be..1a4d7ca3 100644 --- a/src/PhpSpreadsheet/Reader/Ods.php +++ b/src/PhpSpreadsheet/Reader/Ods.php @@ -380,9 +380,8 @@ class Ods extends BaseReader } $columnID = 'A'; - foreach ($childNode->childNodes as $key => $cellData) { - // @var \DOMElement $cellData - + /** @var DOMElement $cellData */ + foreach ($childNode->childNodes as $cellData) { if ($this->getReadFilter() !== null) { if (!$this->getReadFilter()->readCell($columnID, $rowID, $worksheetName)) { ++$columnID; @@ -672,8 +671,9 @@ class Ods extends BaseReader $this->lookForSelectedCells($settings, $spreadsheet, $configNs); } - private function lookForActiveSheet(DOMNode $settings, Spreadsheet $spreadsheet, string $configNs): void + private function lookForActiveSheet(DOMElement $settings, Spreadsheet $spreadsheet, string $configNs): void { + /** @var DOMElement $t */ foreach ($settings->getElementsByTagNameNS($configNs, 'config-item') as $t) { if ($t->getAttributeNs($configNs, 'name') === 'ActiveTable') { try { @@ -687,8 +687,9 @@ class Ods extends BaseReader } } - private function lookForSelectedCells(DOMNode $settings, Spreadsheet $spreadsheet, string $configNs): void + private function lookForSelectedCells(DOMElement $settings, Spreadsheet $spreadsheet, string $configNs): void { + /** @var DOMElement $t */ foreach ($settings->getElementsByTagNameNS($configNs, 'config-item-map-named') as $t) { if ($t->getAttributeNs($configNs, 'name') === 'Tables') { foreach ($t->getElementsByTagNameNS($configNs, 'config-item-map-entry') as $ws) { diff --git a/src/PhpSpreadsheet/Reader/Slk.php b/src/PhpSpreadsheet/Reader/Slk.php index 89d80ffa..c7b6fc82 100644 --- a/src/PhpSpreadsheet/Reader/Slk.php +++ b/src/PhpSpreadsheet/Reader/Slk.php @@ -169,7 +169,7 @@ class Slk extends BaseReader foreach ($rowData as $rowDatum) { switch ($rowDatum[0]) { case 'X': - $columnIndex = substr($rowDatum, 1) - 1; + $columnIndex = (int) substr($rowDatum, 1) - 1; break; case 'Y': @@ -251,7 +251,7 @@ class Slk extends BaseReader } // Bracketed R references are relative to the current row if ($rowReference[0] == '[') { - $rowReference = $row + trim($rowReference, '[]'); + $rowReference = (int) $row + (int) trim($rowReference, '[]'); } $columnReference = $cellReference[4][0]; // Empty C reference is the current column @@ -260,7 +260,7 @@ class Slk extends BaseReader } // Bracketed C references are relative to the current column if ($columnReference[0] == '[') { - $columnReference = $column + trim($columnReference, '[]'); + $columnReference = (int) $column + (int) trim($columnReference, '[]'); } $A1CellReference = Coordinate::stringFromColumnIndex($columnReference) . $rowReference; diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index faa047da..35b55bc0 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -224,7 +224,7 @@ class Xls extends BaseReader /** * Shared fonts. * - * @var array + * @var Font[] */ private $objFonts; @@ -1293,7 +1293,7 @@ class Xls extends BaseReader } } // Named Value - // TODO Provide support for named values + // TODO Provide support for named values } } $this->data = null; @@ -3105,7 +3105,7 @@ class Xls extends BaseReader $len = min($charsLeft, $limitpos - $pos); for ($j = 0; $j < $len; ++$j) { $retstr .= $recordData[$pos + $j] - . chr(0); + . chr(0); } $charsLeft -= $len; $isCompressed = false; @@ -7191,6 +7191,7 @@ class Xls extends BaseReader { [$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell); $baseCol = Coordinate::columnIndexFromString($baseCol) - 1; + $baseRow = (int) $baseRow; // offset: 0; size: 2; index to row (0... 65535) (or offset (-32768... 32767)) $rowIndex = self::getUInt2d($cellAddressStructure, 0); @@ -7368,8 +7369,8 @@ class Xls extends BaseReader */ private function readBIFF8CellRangeAddressB($subData, $baseCell = 'A1') { - [$baseCol, $baseRow] = Coordinate::coordinateFromString($baseCell); - $baseCol = Coordinate::columnIndexFromString($baseCol) - 1; + [$baseCol, $baseRow] = Coordinate::indexesFromString($baseCell); + $baseCol = $baseCol - 1; // TODO: if cell range is just a single cell, should this funciton // not just return e.g. 'A1' and not 'A1:A1' ? diff --git a/src/PhpSpreadsheet/Reader/Xls/MD5.php b/src/PhpSpreadsheet/Reader/Xls/MD5.php index c0417ba6..3e15f641 100644 --- a/src/PhpSpreadsheet/Reader/Xls/MD5.php +++ b/src/PhpSpreadsheet/Reader/Xls/MD5.php @@ -5,12 +5,25 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xls; class MD5 { // Context + + /** + * @var int + */ private $a; + /** + * @var int + */ private $b; + /** + * @var int + */ private $c; + /** + * @var int + */ private $d; /** @@ -56,7 +69,7 @@ class MD5 * * @param string $data Data to add */ - public function add($data): void + public function add(string $data): void { $words = array_values(unpack('V16', $data)); @@ -148,34 +161,34 @@ class MD5 $this->d = ($this->d + $D) & 0xffffffff; } - private static function f($X, $Y, $Z) + private static function f(int $X, int $Y, int $Z) { return ($X & $Y) | ((~$X) & $Z); // X AND Y OR NOT X AND Z } - private static function g($X, $Y, $Z) + private static function g(int $X, int $Y, int $Z) { return ($X & $Z) | ($Y & (~$Z)); // X AND Z OR Y AND NOT Z } - private static function h($X, $Y, $Z) + private static function h(int $X, int $Y, int $Z) { return $X ^ $Y ^ $Z; // X XOR Y XOR Z } - private static function i($X, $Y, $Z) + private static function i(int $X, int $Y, int $Z) { return $Y ^ ($X | (~$Z)); // Y XOR (X OR NOT Z) } - private static function step($func, &$A, $B, $C, $D, $M, $s, $t): void + private static function step($func, int &$A, int $B, int $C, int $D, int $M, int $s, int $t): void { $A = ($A + call_user_func($func, $B, $C, $D) + $M + $t) & 0xffffffff; $A = self::rotate($A, $s); $A = ($B + $A) & 0xffffffff; } - private static function rotate($decimal, $bits) + private static function rotate(int $decimal, int $bits) { $binary = str_pad(decbin($decimal), 32, '0', STR_PAD_LEFT); diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index e47ad7b0..85b6c174 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -272,11 +272,11 @@ class Xlsx extends BaseReader if (!isset($sharedFormulas[(string) $c->f['si']])) { $sharedFormulas[$instance] = ['master' => $r, 'formula' => $value]; } else { - $master = Coordinate::coordinateFromString($sharedFormulas[$instance]['master']); - $current = Coordinate::coordinateFromString($r); + $master = Coordinate::indexesFromString($sharedFormulas[$instance]['master']); + $current = Coordinate::indexesFromString($r); $difference = [0, 0]; - $difference[0] = Coordinate::columnIndexFromString($current[0]) - Coordinate::columnIndexFromString($master[0]); + $difference[0] = $current[0] - $master[0]; $difference[1] = $current[1] - $master[1]; $value = $this->referenceHelper->updateFormulaReferences($sharedFormulas[$instance]['formula'], 'A1', $difference[0], $difference[1]); @@ -1141,7 +1141,7 @@ class Xlsx extends BaseReader )], false ); - $objDrawing->setCoordinates(Coordinate::stringFromColumnIndex(((string) $oneCellAnchor->from->col) + 1) . ($oneCellAnchor->from->row + 1)); + $objDrawing->setCoordinates(Coordinate::stringFromColumnIndex(((int) $oneCellAnchor->from->col) + 1) . ($oneCellAnchor->from->row + 1)); $objDrawing->setOffsetX(Drawing::EMUToPixels($oneCellAnchor->from->colOff)); $objDrawing->setOffsetY(Drawing::EMUToPixels($oneCellAnchor->from->rowOff)); $objDrawing->setResizeProportional(false); @@ -1167,7 +1167,7 @@ class Xlsx extends BaseReader $objDrawing->setWorksheet($docSheet); } elseif ($this->includeCharts && $oneCellAnchor->graphicFrame) { // Exported XLSX from Google Sheets positions charts with a oneCellAnchor - $coordinates = Coordinate::stringFromColumnIndex(((string) $oneCellAnchor->from->col) + 1) . ($oneCellAnchor->from->row + 1); + $coordinates = Coordinate::stringFromColumnIndex(((int) $oneCellAnchor->from->col) + 1) . ($oneCellAnchor->from->row + 1); $offsetX = Drawing::EMUToPixels($oneCellAnchor->from->colOff); $offsetY = Drawing::EMUToPixels($oneCellAnchor->from->rowOff); $width = Drawing::EMUToPixels(self::getArrayItem($oneCellAnchor->ext->attributes(), 'cx')); @@ -1207,7 +1207,7 @@ class Xlsx extends BaseReader )], false ); - $objDrawing->setCoordinates(Coordinate::stringFromColumnIndex(((string) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1)); + $objDrawing->setCoordinates(Coordinate::stringFromColumnIndex(((int) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1)); $objDrawing->setOffsetX(Drawing::EMUToPixels($twoCellAnchor->from->colOff)); $objDrawing->setOffsetY(Drawing::EMUToPixels($twoCellAnchor->from->rowOff)); $objDrawing->setResizeProportional(false); @@ -1233,10 +1233,10 @@ class Xlsx extends BaseReader $objDrawing->setWorksheet($docSheet); } elseif (($this->includeCharts) && ($twoCellAnchor->graphicFrame)) { - $fromCoordinate = Coordinate::stringFromColumnIndex(((string) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1); + $fromCoordinate = Coordinate::stringFromColumnIndex(((int) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1); $fromOffsetX = Drawing::EMUToPixels($twoCellAnchor->from->colOff); $fromOffsetY = Drawing::EMUToPixels($twoCellAnchor->from->rowOff); - $toCoordinate = Coordinate::stringFromColumnIndex(((string) $twoCellAnchor->to->col) + 1) . ($twoCellAnchor->to->row + 1); + $toCoordinate = Coordinate::stringFromColumnIndex(((int) $twoCellAnchor->to->col) + 1) . ($twoCellAnchor->to->row + 1); $toOffsetX = Drawing::EMUToPixels($twoCellAnchor->to->colOff); $toOffsetY = Drawing::EMUToPixels($twoCellAnchor->to->rowOff); $graphic = $twoCellAnchor->graphicFrame->children('http://schemas.openxmlformats.org/drawingml/2006/main')->graphic; @@ -1728,7 +1728,7 @@ class Xlsx extends BaseReader * * @return RichText */ - private function parseRichText($is) + private function parseRichText(?SimpleXMLElement $is) { $value = new RichText(); @@ -1736,6 +1736,8 @@ class Xlsx extends BaseReader $value->createText(StringHelper::controlCharacterOOXML2PHP((string) $is->t)); } else { if (is_object($is->r)) { + + /** @var SimpleXMLElement $run */ foreach ($is->r as $run) { if (!isset($run->rPr)) { $value->createText(StringHelper::controlCharacterOOXML2PHP((string) $run->t)); diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index 5e86c60a..c9fc2f66 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -90,7 +90,7 @@ class Chart break; case 'valAx': - if (isset($chartDetail->title)) { + if (isset($chartDetail->title, $chartDetail->axPos)) { $axisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); $axPos = self::getAttribute($chartDetail->axPos, 'val', 'string'); @@ -355,7 +355,7 @@ class Chart } elseif (isset($seriesDetail->numRef)) { $seriesSource = (string) $seriesDetail->numRef->f; $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, null, null, $marker); - if (isset($seriesDetail->strRef->strCache)) { + if (isset($seriesDetail->numRef->numCache)) { $seriesData = self::chartDataSeriesValues($seriesDetail->numRef->numCache->children($namespacesChartMeta['c'])); $seriesValues ->setFormatCode($seriesData['formatCode']) @@ -539,7 +539,7 @@ class Chart { $plotAttributes = []; if (isset($chartDetail->dLbls)) { - if (isset($chartDetail->dLbls->howLegendKey)) { + if (isset($chartDetail->dLbls->showLegendKey)) { $plotAttributes['showLegendKey'] = self::getAttribute($chartDetail->dLbls->showLegendKey, 'val', 'string'); } if (isset($chartDetail->dLbls->showVal)) { diff --git a/src/PhpSpreadsheet/Reader/Xml.php b/src/PhpSpreadsheet/Reader/Xml.php index 58d38b0d..a900ad9b 100644 --- a/src/PhpSpreadsheet/Reader/Xml.php +++ b/src/PhpSpreadsheet/Reader/Xml.php @@ -422,6 +422,7 @@ class Xml extends BaseReader $worksheetID = 0; $xml_ss = $xml->children($namespaces['ss']); + /** @var null|SimpleXMLElement $worksheetx */ foreach ($xml_ss->Worksheet as $worksheetx) { $worksheet = $worksheetx ?? new SimpleXMLElement(''); $worksheet_ss = self::getAttributes($worksheet, $namespaces['ss']); @@ -748,9 +749,6 @@ class Xml extends BaseReader private static $borderPositions = ['top', 'left', 'bottom', 'right']; - /** - * @param $styleID - */ private function parseStyleBorders($styleID, SimpleXMLElement $styleData, array $namespaces): void { $diagonalDirection = ''; @@ -821,9 +819,6 @@ class Xml extends BaseReader } } - /** - * @param $styleID - */ private function parseStyleFont(string $styleID, SimpleXMLElement $styleAttributes): void { foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValue) { @@ -861,9 +856,6 @@ class Xml extends BaseReader } } - /** - * @param $styleID - */ private function parseStyleInterior($styleID, SimpleXMLElement $styleAttributes): void { foreach ($styleAttributes as $styleAttributeKey => $styleAttributeValuex) { @@ -887,9 +879,6 @@ class Xml extends BaseReader } } - /** - * @param $styleID - */ private function parseStyleNumberFormat($styleID, SimpleXMLElement $styleAttributes): void { $fromFormats = ['\-', '\ ']; diff --git a/src/PhpSpreadsheet/ReferenceHelper.php b/src/PhpSpreadsheet/ReferenceHelper.php index 513f0a53..d4fced37 100644 --- a/src/PhpSpreadsheet/ReferenceHelper.php +++ b/src/PhpSpreadsheet/ReferenceHelper.php @@ -375,17 +375,16 @@ class ReferenceHelper $allCoordinates = $pSheet->getCoordinates(); // Get coordinate of $pBefore - [$beforeColumn, $beforeRow] = Coordinate::coordinateFromString($pBefore); - $beforeColumnIndex = Coordinate::columnIndexFromString($beforeColumn); + [$beforeColumn, $beforeRow] = Coordinate::indexesFromString($pBefore); // Clear cells if we are removing columns or rows $highestColumn = $pSheet->getHighestColumn(); $highestRow = $pSheet->getHighestRow(); // 1. Clear column strips if we are removing columns - if ($pNumCols < 0 && $beforeColumnIndex - 2 + $pNumCols > 0) { + if ($pNumCols < 0 && $beforeColumn - 2 + $pNumCols > 0) { for ($i = 1; $i <= $highestRow - 1; ++$i) { - for ($j = $beforeColumnIndex - 1 + $pNumCols; $j <= $beforeColumnIndex - 2; ++$j) { + for ($j = $beforeColumn - 1 + $pNumCols; $j <= $beforeColumn - 2; ++$j) { $coordinate = Coordinate::stringFromColumnIndex($j + 1) . $i; $pSheet->removeConditionalStyles($coordinate); if ($pSheet->cellExists($coordinate)) { @@ -398,7 +397,7 @@ class ReferenceHelper // 2. Clear row strips if we are removing rows if ($pNumRows < 0 && $beforeRow - 1 + $pNumRows > 0) { - for ($i = $beforeColumnIndex - 1; $i <= Coordinate::columnIndexFromString($highestColumn) - 1; ++$i) { + for ($i = $beforeColumn - 1; $i <= Coordinate::columnIndexFromString($highestColumn) - 1; ++$i) { for ($j = $beforeRow + $pNumRows; $j <= $beforeRow - 1; ++$j) { $coordinate = Coordinate::stringFromColumnIndex($i + 1) . $j; $pSheet->removeConditionalStyles($coordinate); @@ -427,7 +426,7 @@ class ReferenceHelper $newCoordinate = Coordinate::stringFromColumnIndex($cellIndex + $pNumCols) . ($cell->getRow() + $pNumRows); // Should the cell be updated? Move value and cellXf index from one cell to another. - if (($cellIndex >= $beforeColumnIndex) && ($cell->getRow() >= $beforeRow)) { + if (($cellIndex >= $beforeColumn) && ($cell->getRow() >= $beforeRow)) { // Update cell styles $pSheet->getCell($newCoordinate)->setXfIndex($cell->getXfIndex()); @@ -457,15 +456,15 @@ class ReferenceHelper $highestColumn = $pSheet->getHighestColumn(); $highestRow = $pSheet->getHighestRow(); - if ($pNumCols > 0 && $beforeColumnIndex - 2 > 0) { + if ($pNumCols > 0 && $beforeColumn - 2 > 0) { for ($i = $beforeRow; $i <= $highestRow - 1; ++$i) { // Style - $coordinate = Coordinate::stringFromColumnIndex($beforeColumnIndex - 1) . $i; + $coordinate = Coordinate::stringFromColumnIndex($beforeColumn - 1) . $i; if ($pSheet->cellExists($coordinate)) { $xfIndex = $pSheet->getCell($coordinate)->getXfIndex(); $conditionalStyles = $pSheet->conditionalStylesExists($coordinate) ? $pSheet->getConditionalStyles($coordinate) : false; - for ($j = $beforeColumnIndex; $j <= $beforeColumnIndex - 1 + $pNumCols; ++$j) { + for ($j = $beforeColumn; $j <= $beforeColumn - 1 + $pNumCols; ++$j) { $pSheet->getCellByColumnAndRow($j, $i)->setXfIndex($xfIndex); if ($conditionalStyles) { $cloned = []; @@ -480,7 +479,7 @@ class ReferenceHelper } if ($pNumRows > 0 && $beforeRow - 1 > 0) { - for ($i = $beforeColumnIndex; $i <= Coordinate::columnIndexFromString($highestColumn); ++$i) { + for ($i = $beforeColumn; $i <= Coordinate::columnIndexFromString($highestColumn); ++$i) { // Style $coordinate = Coordinate::stringFromColumnIndex($i) . ($beforeRow - 1); if ($pSheet->cellExists($coordinate)) { @@ -502,28 +501,28 @@ class ReferenceHelper } // Update worksheet: column dimensions - $this->adjustColumnDimensions($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustColumnDimensions($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: row dimensions - $this->adjustRowDimensions($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustRowDimensions($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: page breaks - $this->adjustPageBreaks($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustPageBreaks($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: comments - $this->adjustComments($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustComments($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: hyperlinks - $this->adjustHyperlinks($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustHyperlinks($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: data validations - $this->adjustDataValidations($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustDataValidations($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: merge cells - $this->adjustMergeCells($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustMergeCells($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: protected cells - $this->adjustProtectedCells($pSheet, $pBefore, $beforeColumnIndex, $pNumCols, $beforeRow, $pNumRows); + $this->adjustProtectedCells($pSheet, $pBefore, $beforeColumn, $pNumCols, $beforeRow, $pNumRows); // Update worksheet: autofilter $autoFilter = $pSheet->getAutoFilter(); @@ -654,7 +653,7 @@ class ReferenceHelper $toString .= $modified3 . ':' . $modified4; // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more $column = 100000; - $row = 10000000 + trim($match[3], '$'); + $row = 10000000 + (int) trim($match[3], '$'); $cellIndex = $column . $row; $newCellTokens[$cellIndex] = preg_quote($toString, '/'); @@ -705,7 +704,7 @@ class ReferenceHelper [$column, $row] = Coordinate::coordinateFromString($match[3]); // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more $column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000; - $row = trim($row, '$') + 10000000; + $row = (int) trim($row, '$') + 10000000; $cellIndex = $column . $row; $newCellTokens[$cellIndex] = preg_quote($toString, '/'); @@ -731,7 +730,7 @@ class ReferenceHelper [$column, $row] = Coordinate::coordinateFromString($match[3]); // Max worksheet size is 1,048,576 rows by 16,384 columns in Excel 2007, so our adjustments need to be at least one digit more $column = Coordinate::columnIndexFromString(trim($column, '$')) + 100000; - $row = trim($row, '$') + 10000000; + $row = (int) trim($row, '$') + 10000000; $cellIndex = $row . $column; $newCellTokens[$cellIndex] = preg_quote($toString, '/'); @@ -1021,7 +1020,7 @@ class ReferenceHelper // Create new row reference if ($updateRow) { - $newRow = $newRow + $pNumRows; + $newRow = (int) $newRow + $pNumRows; } // Return new reference diff --git a/src/PhpSpreadsheet/RichText/ITextElement.php b/src/PhpSpreadsheet/RichText/ITextElement.php index 69954676..39b70c86 100644 --- a/src/PhpSpreadsheet/RichText/ITextElement.php +++ b/src/PhpSpreadsheet/RichText/ITextElement.php @@ -14,7 +14,7 @@ interface ITextElement /** * Set text. * - * @param $text string Text + * @param string $text Text * * @return ITextElement */ diff --git a/src/PhpSpreadsheet/RichText/TextElement.php b/src/PhpSpreadsheet/RichText/TextElement.php index f8be5d55..26aebc0e 100644 --- a/src/PhpSpreadsheet/RichText/TextElement.php +++ b/src/PhpSpreadsheet/RichText/TextElement.php @@ -35,7 +35,7 @@ class TextElement implements ITextElement /** * Set text. * - * @param $text string Text + * @param string $text Text * * @return $this */ diff --git a/src/PhpSpreadsheet/Shared/Date.php b/src/PhpSpreadsheet/Shared/Date.php index a6cacb6f..49b3425c 100644 --- a/src/PhpSpreadsheet/Shared/Date.php +++ b/src/PhpSpreadsheet/Shared/Date.php @@ -304,8 +304,8 @@ class Date } // Calculate the Julian Date, then subtract the Excel base date (JD 2415020 = 31-Dec-1899 Giving Excel Date of 0) - $century = substr($year, 0, 2); - $decade = substr($year, 2, 2); + $century = (int) substr($year, 0, 2); + $decade = (int) substr($year, 2, 2); $excelDate = floor((146097 * $century) / 4) + floor((1461 * $decade) / 4) + floor((153 * $month + 2) / 5) + $day + 1721119 - $myexcelBaseDate + $excel1900isLeapYear; $excelTime = (($hours * 3600) + ($minutes * 60) + $seconds) / 86400; diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index 4061b370..94e35dfe 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -273,14 +273,8 @@ class Font /** * Get GD text width in pixels for a string of text in a certain font at a certain rotation angle. - * - * @param string $text - * @param \PhpOffice\PhpSpreadsheet\Style\Font - * @param int $rotation - * - * @return int */ - public static function getTextWidthPixelsExact($text, \PhpOffice\PhpSpreadsheet\Style\Font $font, $rotation = 0) + public static function getTextWidthPixelsExact(string $text, \PhpOffice\PhpSpreadsheet\Style\Font $font, int $rotation = 0): int { if (!function_exists('imagettfbbox')) { throw new PhpSpreadsheetException('GD library needs to be enabled'); @@ -350,7 +344,7 @@ class Font } else { // rotated text $columnWidth = $columnWidth * cos(deg2rad($rotation)) - + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation + + $fontSize * abs(sin(deg2rad($rotation))) / 5; // approximation } } @@ -415,35 +409,35 @@ class Font switch ($name) { case 'Arial': $fontFile = ( - $bold ? ($italic ? self::ARIAL_BOLD_ITALIC : self::ARIAL_BOLD) - : ($italic ? self::ARIAL_ITALIC : self::ARIAL) + $bold ? ($italic ? self::ARIAL_BOLD_ITALIC : self::ARIAL_BOLD) + : ($italic ? self::ARIAL_ITALIC : self::ARIAL) ); break; case 'Calibri': $fontFile = ( - $bold ? ($italic ? self::CALIBRI_BOLD_ITALIC : self::CALIBRI_BOLD) - : ($italic ? self::CALIBRI_ITALIC : self::CALIBRI) + $bold ? ($italic ? self::CALIBRI_BOLD_ITALIC : self::CALIBRI_BOLD) + : ($italic ? self::CALIBRI_ITALIC : self::CALIBRI) ); break; case 'Courier New': $fontFile = ( - $bold ? ($italic ? self::COURIER_NEW_BOLD_ITALIC : self::COURIER_NEW_BOLD) - : ($italic ? self::COURIER_NEW_ITALIC : self::COURIER_NEW) + $bold ? ($italic ? self::COURIER_NEW_BOLD_ITALIC : self::COURIER_NEW_BOLD) + : ($italic ? self::COURIER_NEW_ITALIC : self::COURIER_NEW) ); break; case 'Comic Sans MS': $fontFile = ( - $bold ? self::COMIC_SANS_MS_BOLD : self::COMIC_SANS_MS + $bold ? self::COMIC_SANS_MS_BOLD : self::COMIC_SANS_MS ); break; case 'Georgia': $fontFile = ( - $bold ? ($italic ? self::GEORGIA_BOLD_ITALIC : self::GEORGIA_BOLD) - : ($italic ? self::GEORGIA_ITALIC : self::GEORGIA) + $bold ? ($italic ? self::GEORGIA_BOLD_ITALIC : self::GEORGIA_BOLD) + : ($italic ? self::GEORGIA_ITALIC : self::GEORGIA) ); break; @@ -453,8 +447,8 @@ class Font break; case 'Liberation Sans': $fontFile = ( - $bold ? ($italic ? self::LIBERATION_SANS_BOLD_ITALIC : self::LIBERATION_SANS_BOLD) - : ($italic ? self::LIBERATION_SANS_ITALIC : self::LIBERATION_SANS) + $bold ? ($italic ? self::LIBERATION_SANS_BOLD_ITALIC : self::LIBERATION_SANS_BOLD) + : ($italic ? self::LIBERATION_SANS_ITALIC : self::LIBERATION_SANS) ); break; @@ -472,8 +466,8 @@ class Font break; case 'Palatino Linotype': $fontFile = ( - $bold ? ($italic ? self::PALATINO_LINOTYPE_BOLD_ITALIC : self::PALATINO_LINOTYPE_BOLD) - : ($italic ? self::PALATINO_LINOTYPE_ITALIC : self::PALATINO_LINOTYPE) + $bold ? ($italic ? self::PALATINO_LINOTYPE_BOLD_ITALIC : self::PALATINO_LINOTYPE_BOLD) + : ($italic ? self::PALATINO_LINOTYPE_ITALIC : self::PALATINO_LINOTYPE) ); break; @@ -483,28 +477,28 @@ class Font break; case 'Tahoma': $fontFile = ( - $bold ? self::TAHOMA_BOLD : self::TAHOMA + $bold ? self::TAHOMA_BOLD : self::TAHOMA ); break; case 'Times New Roman': $fontFile = ( - $bold ? ($italic ? self::TIMES_NEW_ROMAN_BOLD_ITALIC : self::TIMES_NEW_ROMAN_BOLD) - : ($italic ? self::TIMES_NEW_ROMAN_ITALIC : self::TIMES_NEW_ROMAN) + $bold ? ($italic ? self::TIMES_NEW_ROMAN_BOLD_ITALIC : self::TIMES_NEW_ROMAN_BOLD) + : ($italic ? self::TIMES_NEW_ROMAN_ITALIC : self::TIMES_NEW_ROMAN) ); break; case 'Trebuchet MS': $fontFile = ( - $bold ? ($italic ? self::TREBUCHET_MS_BOLD_ITALIC : self::TREBUCHET_MS_BOLD) - : ($italic ? self::TREBUCHET_MS_ITALIC : self::TREBUCHET_MS) + $bold ? ($italic ? self::TREBUCHET_MS_BOLD_ITALIC : self::TREBUCHET_MS_BOLD) + : ($italic ? self::TREBUCHET_MS_ITALIC : self::TREBUCHET_MS) ); break; case 'Verdana': $fontFile = ( - $bold ? ($italic ? self::VERDANA_BOLD_ITALIC : self::VERDANA_BOLD) - : ($italic ? self::VERDANA_ITALIC : self::VERDANA) + $bold ? ($italic ? self::VERDANA_BOLD_ITALIC : self::VERDANA_BOLD) + : ($italic ? self::VERDANA_ITALIC : self::VERDANA) ); break; @@ -563,13 +557,13 @@ class Font // Exact width can be determined $columnWidth = $pPixels ? self::$defaultColumnWidths[$font->getName()][$font->getSize()]['px'] - : self::$defaultColumnWidths[$font->getName()][$font->getSize()]['width']; + : self::$defaultColumnWidths[$font->getName()][$font->getSize()]['width']; } else { // We don't have data for this particular font and size, use approximation by // extrapolating from Calibri 11 $columnWidth = $pPixels ? self::$defaultColumnWidths['Calibri'][11]['px'] - : self::$defaultColumnWidths['Calibri'][11]['width']; + : self::$defaultColumnWidths['Calibri'][11]['width']; $columnWidth = $columnWidth * $font->getSize() / 11; // Round pixels to closest integer diff --git a/src/PhpSpreadsheet/Shared/JAMA/CholeskyDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/CholeskyDecomposition.php index 2b241d55..27d02176 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/CholeskyDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/CholeskyDecomposition.php @@ -103,7 +103,7 @@ class CholeskyDecomposition /** * Solve A*X = B. * - * @param $B Row-equal matrix + * @param Matrix $B Row-equal matrix * * @return Matrix L * L' * X = B */ @@ -111,7 +111,7 @@ class CholeskyDecomposition { if ($B->getRowDimension() == $this->m) { if ($this->isspd) { - $X = $B->getArrayCopy(); + $X = $B->getArray(); $nx = $B->getColumnDimension(); for ($k = 0; $k < $this->m; ++$k) { diff --git a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php index 5182993c..9cbc9530 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php +++ b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php @@ -456,17 +456,6 @@ class Matrix return $s; } - /** - * uminus. - * - * Unary minus matrix -A - * - * @return Matrix Unary minus matrix - */ - public function uminus() - { - } - /** * plus. * diff --git a/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php index 027706c1..9b51f413 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php @@ -15,9 +15,9 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalculationException; * of simultaneous linear equations. This will fail if isFullRank() * returns false. * - * @author Paul Meagher + * @author Paul Meagher * - * @version 1.1 + * @version 1.1 */ class QRDecomposition { @@ -54,47 +54,43 @@ class QRDecomposition /** * QR Decomposition computed by Householder reflections. * - * @param matrix $A Rectangular matrix + * @param Matrix $A Rectangular matrix */ - public function __construct($A) + public function __construct(Matrix $A) { - if ($A instanceof Matrix) { - // 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; + // 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]); } - } else { - throw new CalculationException(Matrix::ARGUMENT_TYPE_EXCEPTION); + 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; } } @@ -211,7 +207,7 @@ class QRDecomposition if ($this->isFullRank()) { // Copy right hand side $nx = $B->getColumnDimension(); - $X = $B->getArrayCopy(); + $X = $B->getArray(); // Compute Y = transpose(Q)*B for ($k = 0; $k < $this->n; ++$k) { for ($j = 0; $j < $nx; ++$j) { diff --git a/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php index afd9ed0f..6c8999d0 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php @@ -65,7 +65,7 @@ class SingularValueDecomposition public function __construct($Arg) { // Initialize. - $A = $Arg->getArrayCopy(); + $A = $Arg->getArray(); $this->m = $Arg->getRowDimension(); $this->n = $Arg->getColumnDimension(); $nu = min($this->m, $this->n); diff --git a/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php b/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php index cee5cd99..1863ae34 100644 --- a/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php +++ b/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php @@ -42,7 +42,7 @@ class ChainedBlockStream * ole-chainedblockstream://oleInstanceId=1 * @param string $mode only "r" is supported * @param int $options mask of STREAM_REPORT_ERRORS and STREAM_USE_PATH - * @param string &$openedPath absolute path of the opened stream (out parameter) + * @param string $openedPath absolute path of the opened stream (out parameter) * * @return bool true on success */ diff --git a/src/PhpSpreadsheet/Shared/OLE/PPS.php b/src/PhpSpreadsheet/Shared/OLE/PPS.php index a90f193b..104b0d6a 100644 --- a/src/PhpSpreadsheet/Shared/OLE/PPS.php +++ b/src/PhpSpreadsheet/Shared/OLE/PPS.php @@ -200,7 +200,7 @@ class PPS * Updates index and pointers to previous, next and children PPS's for this * PPS. I don't think it'll work with Dir PPS's. * - * @param array &$raList Reference to the array of PPS's for the whole OLE + * @param array $raList Reference to the array of PPS's for the whole OLE * container * @param mixed $to_save * @param mixed $depth diff --git a/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php b/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php index 5466d2bc..2fe41055 100644 --- a/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php +++ b/src/PhpSpreadsheet/Shared/OLE/PPS/Root.php @@ -237,7 +237,7 @@ class Root extends PPS * Saving big data (PPS's with data bigger than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL). * * @param int $iStBlk - * @param array &$raList Reference to array of PPS's + * @param array $raList Reference to array of PPS's */ private function saveBigData($iStBlk, &$raList): void { @@ -267,7 +267,7 @@ class Root extends PPS /** * get small data (PPS's with data smaller than \PhpOffice\PhpSpreadsheet\Shared\OLE::OLE_DATA_SIZE_SMALL). * - * @param array &$raList Reference to array of PPS's + * @param array $raList Reference to array of PPS's * * @return string */ diff --git a/src/PhpSpreadsheet/Shared/OLERead.php b/src/PhpSpreadsheet/Shared/OLERead.php index 7112b090..78417741 100644 --- a/src/PhpSpreadsheet/Shared/OLERead.php +++ b/src/PhpSpreadsheet/Shared/OLERead.php @@ -92,10 +92,8 @@ class OLERead /** * Read the file. - * - * @param $pFilename string Filename */ - public function read($pFilename): void + public function read(string $pFilename): void { File::assertFile($pFilename); diff --git a/src/PhpSpreadsheet/Shared/StringHelper.php b/src/PhpSpreadsheet/Shared/StringHelper.php index a3cc359b..e85ce55d 100644 --- a/src/PhpSpreadsheet/Shared/StringHelper.php +++ b/src/PhpSpreadsheet/Shared/StringHelper.php @@ -556,7 +556,7 @@ class StringHelper * Identify whether a string contains a fractional numeric value, * and convert it to a numeric if it is. * - * @param string &$operand string value to test + * @param string $operand string value to test * * @return bool */ diff --git a/src/PhpSpreadsheet/Shared/Trend/Trend.php b/src/PhpSpreadsheet/Shared/Trend/Trend.php index 24570d59..61d1183a 100644 --- a/src/PhpSpreadsheet/Shared/Trend/Trend.php +++ b/src/PhpSpreadsheet/Shared/Trend/Trend.php @@ -44,7 +44,7 @@ class Trend /** * Cached results for each method when trying to identify which provides the best fit. * - * @var bestFit[] + * @var BestFit[] */ private static $trendCache = []; diff --git a/src/PhpSpreadsheet/Shared/Xls.php b/src/PhpSpreadsheet/Shared/Xls.php index c9eaf378..b3cdbd7d 100644 --- a/src/PhpSpreadsheet/Shared/Xls.php +++ b/src/PhpSpreadsheet/Shared/Xls.php @@ -209,8 +209,7 @@ class Xls */ public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height) { - [$column, $row] = Coordinate::coordinateFromString($coordinates); - $col_start = Coordinate::columnIndexFromString($column); + [$col_start, $row] = Coordinate::indexesFromString($coordinates); $row_start = $row - 1; $x1 = $offsetX; diff --git a/src/PhpSpreadsheet/Style/Border.php b/src/PhpSpreadsheet/Style/Border.php index d11fa0ca..dee1ad4c 100644 --- a/src/PhpSpreadsheet/Style/Border.php +++ b/src/PhpSpreadsheet/Style/Border.php @@ -70,17 +70,19 @@ class Border extends Supervisor */ public function getSharedComponent() { + /** @var Borders $sharedComponent */ + $sharedComponent = $this->parent->getSharedComponent(); switch ($this->parentPropertyName) { case 'bottom': - return $this->parent->getSharedComponent()->getBottom(); + return $sharedComponent->getBottom(); case 'diagonal': - return $this->parent->getSharedComponent()->getDiagonal(); + return $sharedComponent->getDiagonal(); case 'left': - return $this->parent->getSharedComponent()->getLeft(); + return $sharedComponent->getLeft(); case 'right': - return $this->parent->getSharedComponent()->getRight(); + return $sharedComponent->getRight(); case 'top': - return $this->parent->getSharedComponent()->getTop(); + return $sharedComponent->getTop(); } throw new PhpSpreadsheetException('Cannot get shared component for a pseudo-border.'); diff --git a/src/PhpSpreadsheet/Style/Color.php b/src/PhpSpreadsheet/Style/Color.php index acff2e0b..bf5d093f 100644 --- a/src/PhpSpreadsheet/Style/Color.php +++ b/src/PhpSpreadsheet/Style/Color.php @@ -71,14 +71,16 @@ class Color extends Supervisor */ public function getSharedComponent() { + /** @var Border|Fill $sharedComponent */ + $sharedComponent = $this->parent->getSharedComponent(); if ($this->parentPropertyName === 'endColor') { - return $this->parent->getSharedComponent()->getEndColor(); + return $sharedComponent->getEndColor(); } if ($this->parentPropertyName === 'startColor') { - return $this->parent->getSharedComponent()->getStartColor(); + return $sharedComponent->getStartColor(); } - return $this->parent->getSharedComponent()->getColor(); + return $sharedComponent->getColor(); } /** @@ -200,7 +202,7 @@ class Color extends Supervisor * @param bool $hex Flag indicating whether the component should be returned as a hex or a * decimal value * - * @return string The extracted colour component + * @return int|string The extracted colour component */ private static function getColourComponent($RGB, $offset, $hex = true) { @@ -216,7 +218,7 @@ class Color extends Supervisor * @param bool $hex Flag indicating whether the component should be returned as a hex or a * decimal value * - * @return string The red colour component + * @return int|string The red colour component */ public static function getRed($RGB, $hex = true) { @@ -230,7 +232,7 @@ class Color extends Supervisor * @param bool $hex Flag indicating whether the component should be returned as a hex or a * decimal value * - * @return string The green colour component + * @return int|string The green colour component */ public static function getGreen($RGB, $hex = true) { @@ -244,7 +246,7 @@ class Color extends Supervisor * @param bool $hex Flag indicating whether the component should be returned as a hex or a * decimal value * - * @return string The blue colour component + * @return int|string The blue colour component */ public static function getBlue($RGB, $hex = true) { @@ -264,8 +266,11 @@ class Color extends Supervisor $rgba = (strlen($hex) === 8); $adjustPercentage = max(-1.0, min(1.0, $adjustPercentage)); + /** @var int $red */ $red = self::getRed($hex, false); + /** @var int $green */ $green = self::getGreen($hex, false); + /** @var int $blue */ $blue = self::getBlue($hex, false); if ($adjustPercentage > 0) { $red += (255 - $red) * $adjustPercentage; diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php index c6370b86..107969bf 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php @@ -13,8 +13,6 @@ class ConditionalFormatValueObject /** * ConditionalFormatValueObject constructor. * - * @param $type - * @param $value * @param null|mixed $cellFormula */ public function __construct($type, $value = null, $cellFormula = null) diff --git a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php index 943c734b..899bbe43 100644 --- a/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php +++ b/src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php @@ -24,8 +24,6 @@ class ConditionalFormattingRuleExtension /** * ConditionalFormattingRuleExtension constructor. - * - * @param $id */ public function __construct($id = null, string $cfRule = self::CONDITION_EXTENSION_DATABAR) { diff --git a/src/PhpSpreadsheet/Style/Style.php b/src/PhpSpreadsheet/Style/Style.php index d3653ed5..224c0feb 100644 --- a/src/PhpSpreadsheet/Style/Style.php +++ b/src/PhpSpreadsheet/Style/Style.php @@ -202,18 +202,17 @@ class Style extends Supervisor // Calculate range outer borders $rangeStart = Coordinate::coordinateFromString($rangeA); $rangeEnd = Coordinate::coordinateFromString($rangeB); + $rangeStartIndexes = Coordinate::indexesFromString($rangeA); + $rangeEndIndexes = Coordinate::indexesFromString($rangeB); - // Translate column into index - $rangeStart0 = $rangeStart[0]; - $rangeEnd0 = $rangeEnd[0]; - $rangeStart[0] = Coordinate::columnIndexFromString($rangeStart[0]); - $rangeEnd[0] = Coordinate::columnIndexFromString($rangeEnd[0]); + $columnStart = $rangeStart[0]; + $columnEnd = $rangeEnd[0]; // Make sure we can loop upwards on rows and columns - if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) { - $tmp = $rangeStart; - $rangeStart = $rangeEnd; - $rangeEnd = $tmp; + if ($rangeStartIndexes[0] > $rangeEndIndexes[0] && $rangeStartIndexes[1] > $rangeEndIndexes[1]) { + $tmp = $rangeStartIndexes; + $rangeStartIndexes = $rangeEndIndexes; + $rangeEndIndexes = $tmp; } // ADVANCED MODE: @@ -249,19 +248,19 @@ class Style extends Supervisor unset($pStyles['borders']['inside']); // not needed any more } // width and height characteristics of selection, 1, 2, or 3 (for 3 or more) - $xMax = min($rangeEnd[0] - $rangeStart[0] + 1, 3); - $yMax = min($rangeEnd[1] - $rangeStart[1] + 1, 3); + $xMax = min($rangeEndIndexes[0] - $rangeStartIndexes[0] + 1, 3); + $yMax = min($rangeEndIndexes[1] - $rangeStartIndexes[1] + 1, 3); // loop through up to 3 x 3 = 9 regions for ($x = 1; $x <= $xMax; ++$x) { // start column index for region $colStart = ($x == 3) ? - Coordinate::stringFromColumnIndex($rangeEnd[0]) - : Coordinate::stringFromColumnIndex($rangeStart[0] + $x - 1); + Coordinate::stringFromColumnIndex($rangeEndIndexes[0]) + : Coordinate::stringFromColumnIndex($rangeStartIndexes[0] + $x - 1); // end column index for region $colEnd = ($x == 1) ? - Coordinate::stringFromColumnIndex($rangeStart[0]) - : Coordinate::stringFromColumnIndex($rangeEnd[0] - $xMax + $x); + Coordinate::stringFromColumnIndex($rangeStartIndexes[0]) + : Coordinate::stringFromColumnIndex($rangeEndIndexes[0] - $xMax + $x); for ($y = 1; $y <= $yMax; ++$y) { // which edges are touching the region @@ -285,11 +284,11 @@ class Style extends Supervisor // start row index for region $rowStart = ($y == 3) ? - $rangeEnd[1] : $rangeStart[1] + $y - 1; + $rangeEndIndexes[1] : $rangeStartIndexes[1] + $y - 1; // end row index for region $rowEnd = ($y == 1) ? - $rangeStart[1] : $rangeEnd[1] - $yMax + $y; + $rangeStartIndexes[1] : $rangeEndIndexes[1] - $yMax + $y; // build range for region $range = $colStart . $rowStart . ':' . $colEnd . $rowEnd; @@ -349,7 +348,7 @@ class Style extends Supervisor } // First loop through columns, rows, or cells to find out which styles are affected by this operation - $oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStart, $rangeEnd, $rangeStart0, $rangeEnd0, $pStyles); + $oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStartIndexes, $rangeEndIndexes, $columnStart, $columnEnd, $pStyles); // clone each of the affected styles, apply the style array, and add the new styles to the workbook $workbook = $this->getActiveSheet()->getParent(); @@ -372,7 +371,7 @@ class Style extends Supervisor // Loop through columns, rows, or cells again and update the XF index switch ($selectionType) { case 'COLUMN': - for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { + for ($col = $rangeStartIndexes[0]; $col <= $rangeEndIndexes[0]; ++$col) { $columnDimension = $this->getActiveSheet()->getColumnDimensionByColumn($col); $oldXfIndex = $columnDimension->getXfIndex(); $columnDimension->setXfIndex($newXfIndexes[$oldXfIndex]); @@ -380,7 +379,7 @@ class Style extends Supervisor break; case 'ROW': - for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { + for ($row = $rangeStartIndexes[1]; $row <= $rangeEndIndexes[1]; ++$row) { $rowDimension = $this->getActiveSheet()->getRowDimension($row); // row without explicit style should be formatted based on default style $oldXfIndex = $rowDimension->getXfIndex() ?? 0; @@ -389,8 +388,8 @@ class Style extends Supervisor break; case 'CELL': - for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { - for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) { + for ($col = $rangeStartIndexes[0]; $col <= $rangeEndIndexes[0]; ++$col) { + for ($row = $rangeStartIndexes[1]; $row <= $rangeEndIndexes[1]; ++$row) { $cell = $this->getActiveSheet()->getCellByColumnAndRow($col, $row); $oldXfIndex = $cell->getXfIndex(); $cell->setXfIndex($newXfIndexes[$oldXfIndex]); @@ -427,7 +426,7 @@ class Style extends Supervisor return $this; } - private function getOldXfIndexes(string $selectionType, array $rangeStart, array $rangeEnd, string $rangeStart0, string $rangeEnd0, array $pStyles): array + private function getOldXfIndexes(string $selectionType, array $rangeStart, array $rangeEnd, string $columnStart, string $columnEnd, array $pStyles): array { $oldXfIndexes = []; switch ($selectionType) { @@ -435,7 +434,7 @@ class Style extends Supervisor for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) { $oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true; } - foreach ($this->getActiveSheet()->getColumnIterator($rangeStart0, $rangeEnd0) as $columnIterator) { + foreach ($this->getActiveSheet()->getColumnIterator($columnStart, $columnEnd) as $columnIterator) { $cellIterator = $columnIterator->getCellIterator(); $cellIterator->setIterateOnlyExistingCells(true); foreach ($cellIterator as $columnCell) { diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/src/PhpSpreadsheet/Worksheet/AutoFilter.php index dc876ee9..d8912b21 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -780,7 +780,7 @@ class AutoFilter $ruleValues = []; $dataRowCount = $rangeEnd[1] - $rangeStart[1]; $toptenRuleType = null; - $ruleValue = null; + $ruleValue = 0; $ruleOperator = null; foreach ($rules as $rule) { // We should only ever have one Dynamic Filter Rule anyway diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 09ce3e61..f8b6a743 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -96,14 +96,14 @@ class Worksheet implements IComparable /** * Collection of drawings. * - * @var BaseDrawing[] + * @var ArrayObject */ private $drawingCollection; /** * Collection of Chart objects. * - * @var Chart[] + * @var ArrayObject */ private $chartCollection = []; @@ -180,7 +180,7 @@ class Worksheet implements IComparable /** * Collection of breaks. * - * @var array + * @var int[] */ private $breaks = []; @@ -534,7 +534,7 @@ class Worksheet implements IComparable /** * Get collection of drawings. * - * @return BaseDrawing[] + * @return ArrayObject */ public function getDrawingCollection() { @@ -544,7 +544,7 @@ class Worksheet implements IComparable /** * Get collection of charts. * - * @return Chart[] + * @return ArrayObject */ public function getChartCollection() { @@ -1482,7 +1482,7 @@ class Worksheet implements IComparable * Set conditional styles. * * @param string $pCoordinate eg: 'A1' - * @param $pValue Conditional[] + * @param Conditional[] $pValue * * @return $this */ @@ -1640,7 +1640,7 @@ class Worksheet implements IComparable /** * Get breaks. * - * @return array[] + * @return int[] */ public function getBreaks() { diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index 19dfc558..60612737 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -453,10 +453,8 @@ class Html extends BaseWriter // Get worksheet dimension [$min, $max] = explode(':', $sheet->calculateWorksheetDataDimension()); - [$minCol, $minRow] = Coordinate::coordinateFromString($min); - $minCol = Coordinate::columnIndexFromString($minCol); - [$maxCol, $maxRow] = Coordinate::coordinateFromString($max); - $maxCol = Coordinate::columnIndexFromString($maxCol); + [$minCol, $minRow] = Coordinate::indexesFromString($min); + [$maxCol, $maxRow] = Coordinate::indexesFromString($max); [$theadStart, $theadEnd, $tbodyStart] = $this->generateSheetStarts($sheet, $minRow); @@ -1703,11 +1701,11 @@ class Html extends BaseWriter $first = $cells[0]; $last = $cells[1]; - [$fc, $fr] = Coordinate::coordinateFromString($first); - $fc = Coordinate::columnIndexFromString($fc) - 1; + [$fc, $fr] = Coordinate::indexesFromString($first); + $fc = $fc - 1; - [$lc, $lr] = Coordinate::coordinateFromString($last); - $lc = Coordinate::columnIndexFromString($lc) - 1; + [$lc, $lr] = Coordinate::indexesFromString($last); + $lc = $lc - 1; // loop through the individual cells in the individual merge $r = $fr - 1; diff --git a/src/PhpSpreadsheet/Writer/Ods.php b/src/PhpSpreadsheet/Writer/Ods.php index 36f3e9ca..f2d535ac 100644 --- a/src/PhpSpreadsheet/Writer/Ods.php +++ b/src/PhpSpreadsheet/Writer/Ods.php @@ -2,7 +2,6 @@ namespace PhpOffice\PhpSpreadsheet\Writer; -use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; use PhpOffice\PhpSpreadsheet\Writer\Ods\Content; @@ -32,6 +31,41 @@ class Ods extends BaseWriter */ private $spreadSheet; + /** + * @var Content + */ + private $writerPartContent; + + /** + * @var Meta + */ + private $writerPartMeta; + + /** + * @var MetaInf + */ + private $writerPartMetaInf; + + /** + * @var Mimetype + */ + private $writerPartMimetype; + + /** + * @var Settings + */ + private $writerPartSettings; + + /** + * @var Styles + */ + private $writerPartStyles; + + /** + * @var Thumbnails + */ + private $writerPartThumbnails; + /** * Create a new Ods. */ @@ -39,35 +73,48 @@ class Ods extends BaseWriter { $this->setSpreadsheet($spreadsheet); - $writerPartsArray = [ - 'content' => Content::class, - 'meta' => Meta::class, - 'meta_inf' => MetaInf::class, - 'mimetype' => Mimetype::class, - 'settings' => Settings::class, - 'styles' => Styles::class, - 'thumbnails' => Thumbnails::class, - ]; - - foreach ($writerPartsArray as $writer => $class) { - $this->writerParts[$writer] = new $class($this); - } + $this->writerPartContent = new Content($this); + $this->writerPartMeta = new Meta($this); + $this->writerPartMetaInf = new MetaInf($this); + $this->writerPartMimetype = new Mimetype($this); + $this->writerPartSettings = new Settings($this); + $this->writerPartStyles = new Styles($this); + $this->writerPartThumbnails = new Thumbnails($this); } - /** - * Get writer part. - * - * @param string $pPartName Writer part name - * - * @return null|Ods\WriterPart - */ - public function getWriterPart($pPartName) + public function getWriterPartContent(): Content { - if ($pPartName != '' && isset($this->writerParts[strtolower($pPartName)])) { - return $this->writerParts[strtolower($pPartName)]; - } + return $this->writerPartContent; + } - return null; + public function getWriterPartMeta(): Meta + { + return $this->writerPartMeta; + } + + public function getWriterPartMetaInf(): MetaInf + { + return $this->writerPartMetaInf; + } + + public function getWriterPartMimetype(): Mimetype + { + return $this->writerPartMimetype; + } + + public function getWriterPartSettings(): Settings + { + return $this->writerPartSettings; + } + + public function getWriterPartStyles(): Styles + { + return $this->writerPartStyles; + } + + public function getWriterPartThumbnails(): Thumbnails + { + return $this->writerPartThumbnails; } /** @@ -88,13 +135,13 @@ class Ods extends BaseWriter $zip = $this->createZip(); - $zip->addFile('META-INF/manifest.xml', $this->getWriterPart('meta_inf')->writeManifest()); - $zip->addFile('Thumbnails/thumbnail.png', $this->getWriterPart('thumbnails')->writeThumbnail()); - $zip->addFile('content.xml', $this->getWriterPart('content')->write()); - $zip->addFile('meta.xml', $this->getWriterPart('meta')->write()); - $zip->addFile('mimetype', $this->getWriterPart('mimetype')->write()); - $zip->addFile('settings.xml', $this->getWriterPart('settings')->write()); - $zip->addFile('styles.xml', $this->getWriterPart('styles')->write()); + $zip->addFile('META-INF/manifest.xml', $this->getWriterPartMetaInf()->write()); + $zip->addFile('Thumbnails/thumbnail.png', $this->getWriterPartthumbnails()->write()); + $zip->addFile('content.xml', $this->getWriterPartcontent()->write()); + $zip->addFile('meta.xml', $this->getWriterPartmeta()->write()); + $zip->addFile('mimetype', $this->getWriterPartmimetype()->write()); + $zip->addFile('settings.xml', $this->getWriterPartsettings()->write()); + $zip->addFile('styles.xml', $this->getWriterPartstyles()->write()); // Close file try { diff --git a/src/PhpSpreadsheet/Writer/Ods/Content.php b/src/PhpSpreadsheet/Writer/Ods/Content.php index 10238ebf..e4bd1793 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Content.php +++ b/src/PhpSpreadsheet/Writer/Ods/Content.php @@ -39,7 +39,7 @@ class Content extends WriterPart * * @return string XML Output */ - public function write() + public function write(): string { $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { diff --git a/src/PhpSpreadsheet/Writer/Ods/Meta.php b/src/PhpSpreadsheet/Writer/Ods/Meta.php index 365221f7..cd3054c0 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Meta.php +++ b/src/PhpSpreadsheet/Writer/Ods/Meta.php @@ -3,22 +3,17 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; -use PhpOffice\PhpSpreadsheet\Spreadsheet; class Meta extends WriterPart { /** * Write meta.xml to XML format. * - * @param Spreadsheet $spreadsheet - * * @return string XML Output */ - public function write(?Spreadsheet $spreadsheet = null) + public function write(): string { - if (!$spreadsheet) { - $spreadsheet = $this->getParentWriter()->getSpreadsheet(); - } + $spreadsheet = $this->getParentWriter()->getSpreadsheet(); $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { diff --git a/src/PhpSpreadsheet/Writer/Ods/MetaInf.php b/src/PhpSpreadsheet/Writer/Ods/MetaInf.php index c9085cf8..f3f0d5fc 100644 --- a/src/PhpSpreadsheet/Writer/Ods/MetaInf.php +++ b/src/PhpSpreadsheet/Writer/Ods/MetaInf.php @@ -11,7 +11,7 @@ class MetaInf extends WriterPart * * @return string XML Output */ - public function writeManifest() + public function write(): string { $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { diff --git a/src/PhpSpreadsheet/Writer/Ods/Mimetype.php b/src/PhpSpreadsheet/Writer/Ods/Mimetype.php index 4aac3685..e109e6e7 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Mimetype.php +++ b/src/PhpSpreadsheet/Writer/Ods/Mimetype.php @@ -2,18 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; -use PhpOffice\PhpSpreadsheet\Spreadsheet; - class Mimetype extends WriterPart { /** * Write mimetype to plain text format. * - * @param Spreadsheet $spreadsheet - * * @return string XML Output */ - public function write(?Spreadsheet $spreadsheet = null) + public function write(): string { return 'application/vnd.oasis.opendocument.spreadsheet'; } diff --git a/src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php b/src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php index 9edc5c64..ae1c4217 100644 --- a/src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php +++ b/src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php @@ -23,11 +23,13 @@ class NamedExpressions $this->formulaConvertor = $formulaConvertor; } - public function write(): void + public function write(): string { $this->objWriter->startElement('table:named-expressions'); $this->writeExpressions(); $this->objWriter->endElement(); + + return ''; } private function writeExpressions(): void diff --git a/src/PhpSpreadsheet/Writer/Ods/Settings.php b/src/PhpSpreadsheet/Writer/Ods/Settings.php index 301daf03..047bd410 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Settings.php +++ b/src/PhpSpreadsheet/Writer/Ods/Settings.php @@ -4,18 +4,15 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; -use PhpOffice\PhpSpreadsheet\Spreadsheet; class Settings extends WriterPart { /** * Write settings.xml to XML format. * - * @param Spreadsheet $spreadsheet - * * @return string XML Output */ - public function write(?Spreadsheet $spreadsheet = null) + public function write(): string { if ($this->getParentWriter()->getUseDiskCaching()) { $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); @@ -40,7 +37,7 @@ class Settings extends WriterPart $objWriter->startElement('config:config-item-map-indexed'); $objWriter->writeAttribute('config:name', 'Views'); $objWriter->startElement('config:config-item-map-entry'); - $spreadsheet = $spreadsheet ?? $this->getParentWriter()->getSpreadsheet(); + $spreadsheet = $this->getParentWriter()->getSpreadsheet(); $objWriter->startElement('config:config-item'); $objWriter->writeAttribute('config:name', 'ViewId'); diff --git a/src/PhpSpreadsheet/Writer/Ods/Styles.php b/src/PhpSpreadsheet/Writer/Ods/Styles.php index 7ba7eba7..448b1eff 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Styles.php +++ b/src/PhpSpreadsheet/Writer/Ods/Styles.php @@ -3,18 +3,15 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; -use PhpOffice\PhpSpreadsheet\Spreadsheet; class Styles extends WriterPart { /** * Write styles.xml to XML format. * - * @param Spreadsheet $spreadsheet - * * @return string XML Output */ - public function write(?Spreadsheet $spreadsheet = null) + public function write(): string { $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { diff --git a/src/PhpSpreadsheet/Writer/Ods/Thumbnails.php b/src/PhpSpreadsheet/Writer/Ods/Thumbnails.php index dfab0654..db9579d0 100644 --- a/src/PhpSpreadsheet/Writer/Ods/Thumbnails.php +++ b/src/PhpSpreadsheet/Writer/Ods/Thumbnails.php @@ -2,18 +2,14 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Ods; -use PhpOffice\PhpSpreadsheet\Spreadsheet; - class Thumbnails extends WriterPart { /** * Write Thumbnails/thumbnail.png to PNG format. * - * @param Spreadsheet $spreadsheet - * * @return string XML Output */ - public function writeThumbnail(?Spreadsheet $spreadsheet = null) + public function write(): string { return ''; } diff --git a/src/PhpSpreadsheet/Writer/Ods/WriterPart.php b/src/PhpSpreadsheet/Writer/Ods/WriterPart.php index 1982c450..17d5d169 100644 --- a/src/PhpSpreadsheet/Writer/Ods/WriterPart.php +++ b/src/PhpSpreadsheet/Writer/Ods/WriterPart.php @@ -30,4 +30,6 @@ abstract class WriterPart { $this->parentWriter = $writer; } + + abstract public function write(): string; } diff --git a/src/PhpSpreadsheet/Writer/Xls.php b/src/PhpSpreadsheet/Writer/Xls.php index d458fc74..1ee52bdf 100644 --- a/src/PhpSpreadsheet/Writer/Xls.php +++ b/src/PhpSpreadsheet/Writer/Xls.php @@ -23,6 +23,9 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing; use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing; +use PhpOffice\PhpSpreadsheet\Writer\Xls\Parser; +use PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook; +use PhpOffice\PhpSpreadsheet\Writer\Xls\Worksheet; class Xls extends BaseWriter { @@ -64,7 +67,7 @@ class Xls extends BaseWriter /** * Formula parser. * - * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Parser + * @var Parser */ private $parser; @@ -90,12 +93,12 @@ class Xls extends BaseWriter private $documentSummaryInformation; /** - * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook + * @var Workbook */ private $writerWorkbook; /** - * @var \PhpOffice\PhpSpreadsheet\Writer\Xls\Worksheet[] + * @var Worksheet[] */ private $writerWorksheets; @@ -388,7 +391,7 @@ class Xls extends BaseWriter } } - private function processMemoryDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing, string $renderingFunctionx): void + private function processMemoryDrawing(BstoreContainer &$bstoreContainer, MemoryDrawing $drawing, string $renderingFunctionx): void { switch ($renderingFunctionx) { case MemoryDrawing::RENDERING_JPEG: @@ -418,7 +421,7 @@ class Xls extends BaseWriter $bstoreContainer->addBSE($BSE); } - private function processDrawing(BstoreContainer &$bstoreContainer, BaseDrawing $drawing): void + private function processDrawing(BstoreContainer &$bstoreContainer, Drawing $drawing): void { $blipType = null; $blipData = ''; diff --git a/src/PhpSpreadsheet/Writer/Xls/Escher.php b/src/PhpSpreadsheet/Writer/Xls/Escher.php index 1ee2e904..e42139b3 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Escher.php +++ b/src/PhpSpreadsheet/Writer/Xls/Escher.php @@ -420,8 +420,8 @@ class Escher $recType = 0xF010; // start coordinates - [$column, $row] = Coordinate::coordinateFromString($this->object->getStartCoordinates()); - $c1 = Coordinate::columnIndexFromString($column) - 1; + [$column, $row] = Coordinate::indexesFromString($this->object->getStartCoordinates()); + $c1 = $column - 1; $r1 = $row - 1; // start offsetX @@ -431,8 +431,8 @@ class Escher $startOffsetY = $this->object->getStartOffsetY(); // end coordinates - [$column, $row] = Coordinate::coordinateFromString($this->object->getEndCoordinates()); - $c2 = Coordinate::columnIndexFromString($column) - 1; + [$column, $row] = Coordinate::indexesFromString($this->object->getEndCoordinates()); + $c2 = $column - 1; $r2 = $row - 1; // end offsetX diff --git a/src/PhpSpreadsheet/Writer/Xls/Parser.php b/src/PhpSpreadsheet/Writer/Xls/Parser.php index 98b2b5cc..d49459b3 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Parser.php +++ b/src/PhpSpreadsheet/Writer/Xls/Parser.php @@ -527,11 +527,11 @@ class Parser } elseif (preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/mui', $token) && $this->spreadsheet->getDefinedName($token) !== null) { return $this->convertDefinedName($token); // commented so argument number can be processed correctly. See toReversePolish(). - /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/", $token)) - { - return($this->convertFunction($token, $this->_func_args)); - }*/ - // if it's an argument, ignore the token (the argument remains) + /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/", $token)) + { + return($this->convertFunction($token, $this->_func_args)); + }*/ + // if it's an argument, ignore the token (the argument remains) } elseif ($token == 'arg') { return ''; } @@ -597,10 +597,9 @@ class Parser if ($args >= 0) { return pack('Cv', $this->ptg['ptgFuncV'], $this->functions[$token][0]); } + // Variable number of args eg. SUM($i, $j, $k, ..). - if ($args == -1) { - return pack('CCv', $this->ptg['ptgFuncVarV'], $num_args, $this->functions[$token][0]); - } + return pack('CCv', $this->ptg['ptgFuncVarV'], $num_args, $this->functions[$token][0]); } /** @@ -852,10 +851,10 @@ class Parser * called by the addWorksheet() method of the * \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook class. * - * @see \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook::addWorksheet() - * * @param string $name The name of the worksheet being added * @param int $index The index of the worksheet being added + * + * @see \PhpOffice\PhpSpreadsheet\Writer\Xls\Workbook::addWorksheet() */ public function setExtSheet($name, $index): void { @@ -1231,9 +1230,9 @@ class Parser * This function just introduces a ptgParen element in the tree, so that Excel * doesn't get confused when working with a parenthesized formula afterwards. * - * @see fact() - * * @return array The parsed ptg'd tree + * + * @see fact() */ private function parenthesizedExpression() { @@ -1475,6 +1474,7 @@ class Parser } else { $left_tree = ''; } + // add it's left subtree and return. return $left_tree . $this->convertFunction($tree['value'], $tree['right']); } diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index 831c120b..a917185d 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -678,13 +678,13 @@ class Workbook extends BIFFwriter $formulaData = ''; for ($j = 0; $j < $countPrintArea; ++$j) { $printAreaRect = $printArea[$j]; // e.g. A3:J6 - $printAreaRect[0] = Coordinate::coordinateFromString($printAreaRect[0]); - $printAreaRect[1] = Coordinate::coordinateFromString($printAreaRect[1]); + $printAreaRect[0] = Coordinate::indexesFromString($printAreaRect[0]); + $printAreaRect[1] = Coordinate::indexesFromString($printAreaRect[1]); $print_rowmin = $printAreaRect[0][1] - 1; $print_rowmax = $printAreaRect[1][1] - 1; - $print_colmin = Coordinate::columnIndexFromString($printAreaRect[0][0]) - 1; - $print_colmax = Coordinate::columnIndexFromString($printAreaRect[1][0]) - 1; + $print_colmin = $printAreaRect[0][0] - 1; + $print_colmax = $printAreaRect[1][0] - 1; // construct formula data manually because parser does not recognize absolute 3d cell references $formulaData .= pack('Cvvvvv', 0x3B, $i, $print_rowmin, $print_rowmax, $print_colmin, $print_colmax); @@ -756,7 +756,7 @@ class Workbook extends BIFFwriter * Write a short NAME record. * * @param string $name - * @param string $sheetIndex 1-based sheet index the defined name applies to. 0 = global + * @param int $sheetIndex 1-based sheet index the defined name applies to. 0 = global * @param int[][] $rangeBounds range boundaries * @param bool $isHidden * @@ -839,10 +839,9 @@ class Workbook extends BIFFwriter /** * Writes Excel BIFF BOUNDSHEET record. * - * @param Worksheet $sheet Worksheet name * @param int $offset Location of worksheet BOF */ - private function writeBoundSheet($sheet, $offset): void + private function writeBoundSheet(\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet, $offset): void { $sheetname = $sheet->getTitle(); $record = 0x0085; // Record identifier diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php index 8f6015de..fdc05b85 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php @@ -217,8 +217,8 @@ class Worksheet extends BIFFwriter * * @param int $str_total Total number of strings * @param int $str_unique Total number of unique strings - * @param array &$str_table String Table - * @param array &$colors Colour Table + * @param array $str_table String Table + * @param array $colors Colour Table * @param Parser $parser The formula parser created for the Workbook * @param bool $preCalculateFormulas Flag indicating whether formulas should be calculated or just written * @param \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $phpSheet The worksheet to write @@ -512,7 +512,7 @@ class Worksheet extends BIFFwriter // Hyperlinks foreach ($phpSheet->getHyperLinkCollection() as $coordinate => $hyperlink) { - [$column, $row] = Coordinate::coordinateFromString($coordinate); + [$column, $row] = Coordinate::indexesFromString($coordinate); $url = $hyperlink->getUrl(); @@ -526,7 +526,7 @@ class Worksheet extends BIFFwriter $url = 'external:' . $url; } - $this->writeUrl($row - 1, Coordinate::columnIndexFromString($column) - 1, $url); + $this->writeUrl($row - 1, $column - 1, $url); } $this->writeDataValidity(); @@ -587,10 +587,10 @@ class Worksheet extends BIFFwriter $lastCell = $explodes[1]; } - $firstCellCoordinates = Coordinate::coordinateFromString($firstCell); // e.g. [0, 1] - $lastCellCoordinates = Coordinate::coordinateFromString($lastCell); // e.g. [1, 6] + $firstCellCoordinates = Coordinate::indexesFromString($firstCell); // e.g. [0, 1] + $lastCellCoordinates = Coordinate::indexesFromString($lastCell); // e.g. [1, 6] - return pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, Coordinate::columnIndexFromString($firstCellCoordinates[0]) - 1, Coordinate::columnIndexFromString($lastCellCoordinates[0]) - 1); + return pack('vvvv', $firstCellCoordinates[1] - 1, $lastCellCoordinates[1] - 1, $firstCellCoordinates[0] - 1, $lastCellCoordinates[0] - 1); } /** @@ -1455,10 +1455,10 @@ class Worksheet extends BIFFwriter // extract the row and column indexes $range = Coordinate::splitRange($mergeCell); [$first, $last] = $range[0]; - [$firstColumn, $firstRow] = Coordinate::coordinateFromString($first); - [$lastColumn, $lastRow] = Coordinate::coordinateFromString($last); + [$firstColumn, $firstRow] = Coordinate::indexesFromString($first); + [$lastColumn, $lastRow] = Coordinate::indexesFromString($last); - $recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, Coordinate::columnIndexFromString($firstColumn) - 1, Coordinate::columnIndexFromString($lastColumn) - 1); + $recordData .= pack('vvvv', $firstRow - 1, $lastRow - 1, $firstColumn - 1, $lastColumn - 1); // flush record if we have reached limit for number of merged cells, or reached final merged cell if ($j == $maxCountMergeCellsPerRecord || $i == $countMergeCells) { @@ -1601,76 +1601,37 @@ class Worksheet extends BIFFwriter */ private function writePanes(): void { - $panes = []; - if ($this->phpSheet->getFreezePane()) { - [$column, $row] = Coordinate::coordinateFromString($this->phpSheet->getFreezePane()); - $panes[0] = Coordinate::columnIndexFromString($column) - 1; - $panes[1] = $row - 1; - - [$leftMostColumn, $topRow] = Coordinate::coordinateFromString($this->phpSheet->getTopLeftCell()); - //Coordinates are zero-based in xls files - $panes[2] = $topRow - 1; - $panes[3] = Coordinate::columnIndexFromString($leftMostColumn) - 1; - } else { + if (!$this->phpSheet->getFreezePane()) { // thaw panes return; } - $x = $panes[0] ?? null; - $y = $panes[1] ?? null; - $rwTop = $panes[2] ?? null; - $colLeft = $panes[3] ?? null; - if (count($panes) > 4) { // if Active pane was received - $pnnAct = $panes[4]; - } else { - $pnnAct = null; - } + [$column, $row] = Coordinate::indexesFromString($this->phpSheet->getFreezePane()); + $x = $column - 1; + $y = $row - 1; + + [$leftMostColumn, $topRow] = Coordinate::indexesFromString($this->phpSheet->getTopLeftCell()); + //Coordinates are zero-based in xls files + $rwTop = $topRow - 1; + $colLeft = $leftMostColumn - 1; + $record = 0x0041; // Record identifier $length = 0x000A; // Number of bytes to follow - // Code specific to frozen or thawed panes. - if ($this->phpSheet->getFreezePane()) { - // Set default values for $rwTop and $colLeft - if (!isset($rwTop)) { - $rwTop = $y; - } - if (!$colLeft) { - $colLeft = $x; - } - } else { - // Set default values for $rwTop and $colLeft - if (!isset($rwTop)) { - $rwTop = 0; - } - if (!$colLeft) { - $colLeft = 0; - } - - // Convert Excel's row and column units to the internal units. - // The default row height is 12.75 - // The default column width is 8.43 - // The following slope and intersection values were interpolated. - // - $y = 20 * $y + 255; - $x = 113.879 * $x + 390; - } - // Determine which pane should be active. There is also the undocumented // option to override this should it be necessary: may be removed later. - // - if (!$pnnAct) { - if ($x != 0 && $y != 0) { - $pnnAct = 0; // Bottom right - } - if ($x != 0 && $y == 0) { - $pnnAct = 1; // Top right - } - if ($x == 0 && $y != 0) { - $pnnAct = 2; // Bottom left - } - if ($x == 0 && $y == 0) { - $pnnAct = 3; // Top left - } + $pnnAct = null; + if ($x != 0 && $y != 0) { + $pnnAct = 0; // Bottom right + } + if ($x != 0 && $y == 0) { + $pnnAct = 1; // Top right + } + if ($x == 0 && $y != 0) { + $pnnAct = 2; // Bottom left + } + if ($x == 0 && $y == 0) { + $pnnAct = 3; // Top left } $this->activePane = $pnnAct; // Used in writeSelection @@ -4427,10 +4388,7 @@ class Worksheet extends BIFFwriter $arrConditional[] = $conditional->getHashCode(); } // Cells - $arrCoord = Coordinate::coordinateFromString($cellCoordinate); - if (!is_numeric($arrCoord[0])) { - $arrCoord[0] = Coordinate::columnIndexFromString($arrCoord[0]); - } + $arrCoord = Coordinate::indexesFromString($cellCoordinate); if ($numColumnMin === null || ($numColumnMin > $arrCoord[0])) { $numColumnMin = $arrCoord[0]; } diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index d71541c8..ea1ce2f2 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -5,8 +5,13 @@ namespace PhpOffice\PhpSpreadsheet\Writer; use PhpOffice\PhpSpreadsheet\Calculation\Calculation; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\HashTable; -use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Style\Borders; +use PhpOffice\PhpSpreadsheet\Style\Conditional; +use PhpOffice\PhpSpreadsheet\Style\Fill; +use PhpOffice\PhpSpreadsheet\Style\Font; +use PhpOffice\PhpSpreadsheet\Style\NumberFormat; +use PhpOffice\PhpSpreadsheet\Worksheet\BaseDrawing; use PhpOffice\PhpSpreadsheet\Worksheet\Drawing as WorksheetDrawing; use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; @@ -37,13 +42,6 @@ class Xlsx extends BaseWriter */ private $office2003compatibility = false; - /** - * Private writer parts. - * - * @var Xlsx\WriterPart[] - */ - private $writerParts = []; - /** * Private Spreadsheet. * @@ -61,49 +59,49 @@ class Xlsx extends BaseWriter /** * Private unique Conditional HashTable. * - * @var HashTable + * @var HashTable */ private $stylesConditionalHashTable; /** * Private unique Style HashTable. * - * @var HashTable + * @var HashTable<\PhpOffice\PhpSpreadsheet\Style\Style> */ private $styleHashTable; /** * Private unique Fill HashTable. * - * @var HashTable + * @var HashTable */ private $fillHashTable; /** * Private unique \PhpOffice\PhpSpreadsheet\Style\Font HashTable. * - * @var HashTable + * @var HashTable */ private $fontHashTable; /** * Private unique Borders HashTable. * - * @var HashTable + * @var HashTable */ private $bordersHashTable; /** * Private unique NumberFormat HashTable. * - * @var HashTable + * @var HashTable */ private $numFmtHashTable; /** * Private unique \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\BaseDrawing HashTable. * - * @var HashTable + * @var HashTable */ private $drawingHashTable; @@ -114,6 +112,71 @@ class Xlsx extends BaseWriter */ private $zip; + /** + * @var Chart + */ + private $writerPartChart; + + /** + * @var Comments + */ + private $writerPartComments; + + /** + * @var ContentTypes + */ + private $writerPartContentTypes; + + /** + * @var DocProps + */ + private $writerPartDocProps; + + /** + * @var Drawing + */ + private $writerPartDrawing; + + /** + * @var Rels + */ + private $writerPartRels; + + /** + * @var RelsRibbon + */ + private $writerPartRelsRibbon; + + /** + * @var RelsVBA + */ + private $writerPartRelsVBA; + + /** + * @var StringTable + */ + private $writerPartStringTable; + + /** + * @var Style + */ + private $writerPartStyle; + + /** + * @var Theme + */ + private $writerPartTheme; + + /** + * @var Workbook + */ + private $writerPartWorkbook; + + /** + * @var Worksheet + */ + private $writerPartWorksheet; + /** * Create a new Xlsx Writer. */ @@ -122,53 +185,93 @@ class Xlsx extends BaseWriter // Assign PhpSpreadsheet $this->setSpreadsheet($spreadsheet); - $writerPartsArray = [ - 'stringtable' => StringTable::class, - 'contenttypes' => ContentTypes::class, - 'docprops' => DocProps::class, - 'rels' => Rels::class, - 'theme' => Theme::class, - 'style' => Style::class, - 'workbook' => Workbook::class, - 'worksheet' => Worksheet::class, - 'drawing' => Drawing::class, - 'comments' => Comments::class, - 'chart' => Chart::class, - 'relsvba' => RelsVBA::class, - 'relsribbonobjects' => RelsRibbon::class, - ]; - - // Initialise writer parts - // and Assign their parent IWriters - foreach ($writerPartsArray as $writer => $class) { - $this->writerParts[$writer] = new $class($this); - } - - $hashTablesArray = ['stylesConditionalHashTable', 'fillHashTable', 'fontHashTable', - 'bordersHashTable', 'numFmtHashTable', 'drawingHashTable', - 'styleHashTable', - ]; + $this->writerPartChart = new Chart($this); + $this->writerPartComments = new Comments($this); + $this->writerPartContentTypes = new ContentTypes($this); + $this->writerPartDocProps = new DocProps($this); + $this->writerPartDrawing = new Drawing($this); + $this->writerPartRels = new Rels($this); + $this->writerPartRelsRibbon = new RelsRibbon($this); + $this->writerPartRelsVBA = new RelsVBA($this); + $this->writerPartStringTable = new StringTable($this); + $this->writerPartStyle = new Style($this); + $this->writerPartTheme = new Theme($this); + $this->writerPartWorkbook = new Workbook($this); + $this->writerPartWorksheet = new Worksheet($this); // Set HashTable variables - foreach ($hashTablesArray as $tableName) { - $this->$tableName = new HashTable(); - } + $this->bordersHashTable = new HashTable(); + $this->drawingHashTable = new HashTable(); + $this->fillHashTable = new HashTable(); + $this->fontHashTable = new HashTable(); + $this->numFmtHashTable = new HashTable(); + $this->styleHashTable = new HashTable(); + $this->stylesConditionalHashTable = new HashTable(); } - /** - * Get writer part. - * - * @param string $pPartName Writer part name - * - * @return \PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart - */ - public function getWriterPart($pPartName) + public function getWriterPartChart(): Chart { - if ($pPartName != '' && isset($this->writerParts[strtolower($pPartName)])) { - return $this->writerParts[strtolower($pPartName)]; - } + return $this->writerPartChart; + } - return null; + public function getWriterPartComments(): Comments + { + return $this->writerPartComments; + } + + public function getWriterPartContentTypes(): ContentTypes + { + return $this->writerPartContentTypes; + } + + public function getWriterPartDocProps(): DocProps + { + return $this->writerPartDocProps; + } + + public function getWriterPartDrawing(): Drawing + { + return $this->writerPartDrawing; + } + + public function getWriterPartRels(): Rels + { + return $this->writerPartRels; + } + + public function getWriterPartRelsRibbon(): RelsRibbon + { + return $this->writerPartRelsRibbon; + } + + public function getWriterPartRelsVBA(): RelsVBA + { + return $this->writerPartRelsVBA; + } + + public function getWriterPartStringTable(): StringTable + { + return $this->writerPartStringTable; + } + + public function getWriterPartStyle(): Style + { + return $this->writerPartStyle; + } + + public function getWriterPartTheme(): Theme + { + return $this->writerPartTheme; + } + + public function getWriterPartWorkbook(): Workbook + { + return $this->writerPartWorkbook; + } + + public function getWriterPartWorksheet(): Worksheet + { + return $this->writerPartWorksheet; } /** @@ -192,19 +295,19 @@ class Xlsx extends BaseWriter // Create string lookup table $this->stringTable = []; for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { - $this->stringTable = $this->getWriterPart('StringTable')->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable); + $this->stringTable = $this->getWriterPartStringTable()->createStringTable($this->spreadSheet->getSheet($i), $this->stringTable); } // Create styles dictionaries - $this->styleHashTable->addFromSource($this->getWriterPart('Style')->allStyles($this->spreadSheet)); - $this->stylesConditionalHashTable->addFromSource($this->getWriterPart('Style')->allConditionalStyles($this->spreadSheet)); - $this->fillHashTable->addFromSource($this->getWriterPart('Style')->allFills($this->spreadSheet)); - $this->fontHashTable->addFromSource($this->getWriterPart('Style')->allFonts($this->spreadSheet)); - $this->bordersHashTable->addFromSource($this->getWriterPart('Style')->allBorders($this->spreadSheet)); - $this->numFmtHashTable->addFromSource($this->getWriterPart('Style')->allNumberFormats($this->spreadSheet)); + $this->styleHashTable->addFromSource($this->getWriterPartStyle()->allStyles($this->spreadSheet)); + $this->stylesConditionalHashTable->addFromSource($this->getWriterPartStyle()->allConditionalStyles($this->spreadSheet)); + $this->fillHashTable->addFromSource($this->getWriterPartStyle()->allFills($this->spreadSheet)); + $this->fontHashTable->addFromSource($this->getWriterPartStyle()->allFonts($this->spreadSheet)); + $this->bordersHashTable->addFromSource($this->getWriterPartStyle()->allBorders($this->spreadSheet)); + $this->numFmtHashTable->addFromSource($this->getWriterPartStyle()->allNumberFormats($this->spreadSheet)); // Create drawing dictionary - $this->drawingHashTable->addFromSource($this->getWriterPart('Drawing')->allDrawings($this->spreadSheet)); + $this->drawingHashTable->addFromSource($this->getWriterPartDrawing()->allDrawings($this->spreadSheet)); $options = new Archive(); $options->setEnableZip64(false); @@ -213,7 +316,7 @@ class Xlsx extends BaseWriter $this->zip = new ZipStream(null, $options); // Add [Content_Types].xml to ZIP file - $this->addZipFile('[Content_Types].xml', $this->getWriterPart('ContentTypes')->writeContentTypes($this->spreadSheet, $this->includeCharts)); + $this->addZipFile('[Content_Types].xml', $this->getWriterPartContentTypes()->writeContentTypes($this->spreadSheet, $this->includeCharts)); //if hasMacros, add the vbaProject.bin file, Certificate file(if exists) if ($this->spreadSheet->hasMacros()) { @@ -225,7 +328,7 @@ class Xlsx extends BaseWriter //signed macros ? // Yes : add the certificate file and the related rels file $this->addZipFile('xl/vbaProjectSignature.bin', $this->spreadSheet->getMacrosCertificate()); - $this->addZipFile('xl/_rels/vbaProject.bin.rels', $this->getWriterPart('RelsVBA')->writeVBARelationships($this->spreadSheet)); + $this->addZipFile('xl/_rels/vbaProject.bin.rels', $this->getWriterPartRelsVBA()->writeVBARelationships($this->spreadSheet)); } } } @@ -240,43 +343,43 @@ class Xlsx extends BaseWriter $this->addZipFile($tmpRootPath . $aPath, $aContent); } //the rels for files - $this->addZipFile($tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels', $this->getWriterPart('RelsRibbonObjects')->writeRibbonRelationships($this->spreadSheet)); + $this->addZipFile($tmpRootPath . '_rels/' . basename($tmpRibbonTarget) . '.rels', $this->getWriterPartRelsRibbon()->writeRibbonRelationships($this->spreadSheet)); } } // Add relationships to ZIP file - $this->addZipFile('_rels/.rels', $this->getWriterPart('Rels')->writeRelationships($this->spreadSheet)); - $this->addZipFile('xl/_rels/workbook.xml.rels', $this->getWriterPart('Rels')->writeWorkbookRelationships($this->spreadSheet)); + $this->addZipFile('_rels/.rels', $this->getWriterPartRels()->writeRelationships($this->spreadSheet)); + $this->addZipFile('xl/_rels/workbook.xml.rels', $this->getWriterPartRels()->writeWorkbookRelationships($this->spreadSheet)); // Add document properties to ZIP file - $this->addZipFile('docProps/app.xml', $this->getWriterPart('DocProps')->writeDocPropsApp($this->spreadSheet)); - $this->addZipFile('docProps/core.xml', $this->getWriterPart('DocProps')->writeDocPropsCore($this->spreadSheet)); - $customPropertiesPart = $this->getWriterPart('DocProps')->writeDocPropsCustom($this->spreadSheet); + $this->addZipFile('docProps/app.xml', $this->getWriterPartDocProps()->writeDocPropsApp($this->spreadSheet)); + $this->addZipFile('docProps/core.xml', $this->getWriterPartDocProps()->writeDocPropsCore($this->spreadSheet)); + $customPropertiesPart = $this->getWriterPartDocProps()->writeDocPropsCustom($this->spreadSheet); if ($customPropertiesPart !== null) { $this->addZipFile('docProps/custom.xml', $customPropertiesPart); } // Add theme to ZIP file - $this->addZipFile('xl/theme/theme1.xml', $this->getWriterPart('Theme')->writeTheme($this->spreadSheet)); + $this->addZipFile('xl/theme/theme1.xml', $this->getWriterPartTheme()->writeTheme($this->spreadSheet)); // Add string table to ZIP file - $this->addZipFile('xl/sharedStrings.xml', $this->getWriterPart('StringTable')->writeStringTable($this->stringTable)); + $this->addZipFile('xl/sharedStrings.xml', $this->getWriterPartStringTable()->writeStringTable($this->stringTable)); // Add styles to ZIP file - $this->addZipFile('xl/styles.xml', $this->getWriterPart('Style')->writeStyles($this->spreadSheet)); + $this->addZipFile('xl/styles.xml', $this->getWriterPartStyle()->writeStyles($this->spreadSheet)); // Add workbook to ZIP file - $this->addZipFile('xl/workbook.xml', $this->getWriterPart('Workbook')->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas)); + $this->addZipFile('xl/workbook.xml', $this->getWriterPartWorkbook()->writeWorkbook($this->spreadSheet, $this->preCalculateFormulas)); $chartCount = 0; // Add worksheets for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { - $this->addZipFile('xl/worksheets/sheet' . ($i + 1) . '.xml', $this->getWriterPart('Worksheet')->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts)); + $this->addZipFile('xl/worksheets/sheet' . ($i + 1) . '.xml', $this->getWriterPartWorksheet()->writeWorksheet($this->spreadSheet->getSheet($i), $this->stringTable, $this->includeCharts)); if ($this->includeCharts) { $charts = $this->spreadSheet->getSheet($i)->getChartCollection(); if (count($charts) > 0) { foreach ($charts as $chart) { - $this->addZipFile('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPart('Chart')->writeChart($chart, $this->preCalculateFormulas)); + $this->addZipFile('xl/charts/chart' . ($chartCount + 1) . '.xml', $this->getWriterPartChart()->writeChart($chart, $this->preCalculateFormulas)); ++$chartCount; } } @@ -287,7 +390,7 @@ class Xlsx extends BaseWriter // Add worksheet relationships (drawings, ...) for ($i = 0; $i < $this->spreadSheet->getSheetCount(); ++$i) { // Add relationships - $this->addZipFile('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts)); + $this->addZipFile('xl/worksheets/_rels/sheet' . ($i + 1) . '.xml.rels', $this->getWriterPartRels()->writeWorksheetRelationships($this->spreadSheet->getSheet($i), ($i + 1), $this->includeCharts)); // Add unparsedLoadedData $sheetCodeName = $this->spreadSheet->getSheet($i)->getCodeName(); @@ -312,13 +415,13 @@ class Xlsx extends BaseWriter // Add drawing and image relationship parts if (($drawingCount > 0) || ($chartCount > 0)) { // Drawing relationships - $this->addZipFile('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPart('Rels')->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts)); + $this->addZipFile('xl/drawings/_rels/drawing' . ($i + 1) . '.xml.rels', $this->getWriterPartRels()->writeDrawingRelationships($this->spreadSheet->getSheet($i), $chartRef1, $this->includeCharts)); // Drawings - $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); + $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPartDrawing()->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); } elseif (isset($unparsedLoadedData['sheets'][$sheetCodeName]['drawingAlternateContents'])) { // Drawings - $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPart('Drawing')->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); + $this->addZipFile('xl/drawings/drawing' . ($i + 1) . '.xml', $this->getWriterPartDrawing()->writeDrawings($this->spreadSheet->getSheet($i), $this->includeCharts)); } // Add unparsed drawings @@ -335,10 +438,10 @@ class Xlsx extends BaseWriter // Add comment relationship parts if (count($this->spreadSheet->getSheet($i)->getComments()) > 0) { // VML Comments - $this->addZipFile('xl/drawings/vmlDrawing' . ($i + 1) . '.vml', $this->getWriterPart('Comments')->writeVMLComments($this->spreadSheet->getSheet($i))); + $this->addZipFile('xl/drawings/vmlDrawing' . ($i + 1) . '.vml', $this->getWriterPartComments()->writeVMLComments($this->spreadSheet->getSheet($i))); // Comments - $this->addZipFile('xl/comments' . ($i + 1) . '.xml', $this->getWriterPart('Comments')->writeComments($this->spreadSheet->getSheet($i))); + $this->addZipFile('xl/comments' . ($i + 1) . '.xml', $this->getWriterPartComments()->writeComments($this->spreadSheet->getSheet($i))); } // Add unparsed relationship parts @@ -351,10 +454,10 @@ class Xlsx extends BaseWriter // Add header/footer relationship parts if (count($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages()) > 0) { // VML Drawings - $this->addZipFile('xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml', $this->getWriterPart('Drawing')->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i))); + $this->addZipFile('xl/drawings/vmlDrawingHF' . ($i + 1) . '.vml', $this->getWriterPartDrawing()->writeVMLHeaderFooterImages($this->spreadSheet->getSheet($i))); // VML Drawing relationships - $this->addZipFile('xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels', $this->getWriterPart('Rels')->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i))); + $this->addZipFile('xl/drawings/_rels/vmlDrawingHF' . ($i + 1) . '.vml.rels', $this->getWriterPartRels()->writeHeaderFooterDrawingRelationships($this->spreadSheet->getSheet($i))); // Media foreach ($this->spreadSheet->getSheet($i)->getHeaderFooter()->getImages() as $image) { @@ -445,7 +548,7 @@ class Xlsx extends BaseWriter /** * Get Style HashTable. * - * @return HashTable + * @return HashTable<\PhpOffice\PhpSpreadsheet\Style\Style> */ public function getStyleHashTable() { @@ -455,7 +558,7 @@ class Xlsx extends BaseWriter /** * Get Conditional HashTable. * - * @return HashTable + * @return HashTable */ public function getStylesConditionalHashTable() { @@ -465,7 +568,7 @@ class Xlsx extends BaseWriter /** * Get Fill HashTable. * - * @return HashTable + * @return HashTable */ public function getFillHashTable() { @@ -475,7 +578,7 @@ class Xlsx extends BaseWriter /** * Get \PhpOffice\PhpSpreadsheet\Style\Font HashTable. * - * @return HashTable + * @return HashTable */ public function getFontHashTable() { @@ -485,7 +588,7 @@ class Xlsx extends BaseWriter /** * Get Borders HashTable. * - * @return HashTable + * @return HashTable */ public function getBordersHashTable() { @@ -495,7 +598,7 @@ class Xlsx extends BaseWriter /** * Get NumberFormat HashTable. * - * @return HashTable + * @return HashTable */ public function getNumFmtHashTable() { @@ -505,7 +608,7 @@ class Xlsx extends BaseWriter /** * Get \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet\BaseDrawing HashTable. * - * @return HashTable + * @return HashTable */ public function getDrawingHashTable() { diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php index 19da32c4..eefae529 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php @@ -129,7 +129,7 @@ class Chart extends WriterPart if ((is_array($caption)) && (count($caption) > 0)) { $caption = $caption[0]; } - $this->getParentWriter()->getWriterPart('stringtable')->writeRichTextForCharts($objWriter, $caption, 'a'); + $this->getParentWriter()->getWriterPartstringtable()->writeRichTextForCharts($objWriter, $caption, 'a'); $objWriter->endElement(); $objWriter->endElement(); @@ -1040,9 +1040,9 @@ class Chart extends WriterPart * @param DataSeries $plotGroup * @param string $groupType Type of plot for dataseries * @param XMLWriter $objWriter XML Writer - * @param bool &$catIsMultiLevelSeries Is category a multi-series category - * @param bool &$valIsMultiLevelSeries Is value set a multi-series set - * @param string &$plotGroupingType Type of grouping for multi-series values + * @param bool $catIsMultiLevelSeries Is category a multi-series category + * @param bool $valIsMultiLevelSeries Is value set a multi-series set + * @param string $plotGroupingType Type of grouping for multi-series values */ private function writePlotGroup($plotGroup, $groupType, $objWriter, &$catIsMultiLevelSeries, &$valIsMultiLevelSeries, &$plotGroupingType): void { diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Comments.php b/src/PhpSpreadsheet/Writer/Xlsx/Comments.php index 73c4308b..51f4248c 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Comments.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Comments.php @@ -79,7 +79,7 @@ class Comments extends WriterPart // text $objWriter->startElement('text'); - $this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $pComment->getText()); + $this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $pComment->getText()); $objWriter->endElement(); $objWriter->endElement(); @@ -165,8 +165,7 @@ class Comments extends WriterPart private function writeVMLComment(XMLWriter $objWriter, $pCellReference, Comment $pComment): void { // Metadata - [$column, $row] = Coordinate::coordinateFromString($pCellReference); - $column = Coordinate::columnIndexFromString($column); + [$column, $row] = Coordinate::indexesFromString($pCellReference); $id = 1024 + $column + $row; $id = substr($id, 0, 4); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php b/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php index 1713b982..a4b09d39 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Drawing.php @@ -84,22 +84,22 @@ class Drawing extends WriterPart public function writeChart(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Chart\Chart $pChart, $pRelationId = -1): void { $tl = $pChart->getTopLeftPosition(); - $tl['colRow'] = Coordinate::coordinateFromString($tl['cell']); + $tlColRow = Coordinate::indexesFromString($tl['cell']); $br = $pChart->getBottomRightPosition(); - $br['colRow'] = Coordinate::coordinateFromString($br['cell']); + $brColRow = Coordinate::indexesFromString($br['cell']); $objWriter->startElement('xdr:twoCellAnchor'); $objWriter->startElement('xdr:from'); - $objWriter->writeElement('xdr:col', Coordinate::columnIndexFromString($tl['colRow'][0]) - 1); + $objWriter->writeElement('xdr:col', $tlColRow[0] - 1); $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['xOffset'])); - $objWriter->writeElement('xdr:row', $tl['colRow'][1] - 1); + $objWriter->writeElement('xdr:row', $tlColRow[1] - 1); $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($tl['yOffset'])); $objWriter->endElement(); $objWriter->startElement('xdr:to'); - $objWriter->writeElement('xdr:col', Coordinate::columnIndexFromString($br['colRow'][0]) - 1); + $objWriter->writeElement('xdr:col', $brColRow[0] - 1); $objWriter->writeElement('xdr:colOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['xOffset'])); - $objWriter->writeElement('xdr:row', $br['colRow'][1] - 1); + $objWriter->writeElement('xdr:row', $brColRow[1] - 1); $objWriter->writeElement('xdr:rowOff', \PhpOffice\PhpSpreadsheet\Shared\Drawing::pixelsToEMU($br['yOffset'])); $objWriter->endElement(); @@ -158,8 +158,7 @@ class Drawing extends WriterPart // xdr:oneCellAnchor $objWriter->startElement('xdr:oneCellAnchor'); // Image location - $aCoordinates = Coordinate::coordinateFromString($pDrawing->getCoordinates()); - $aCoordinates[0] = Coordinate::columnIndexFromString($aCoordinates[0]); + $aCoordinates = Coordinate::indexesFromString($pDrawing->getCoordinates()); // xdr:from $objWriter->startElement('xdr:from'); @@ -433,7 +432,7 @@ class Drawing extends WriterPart { // Calculate object id preg_match('{(\d+)}', md5($pReference), $m); - $id = 1500 + (substr($m[1], 0, 2) * 1); + $id = 1500 + ((int) substr($m[1], 0, 2) * 1); // Calculate offset $width = $pImage->getWidth(); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Rels.php b/src/PhpSpreadsheet/Writer/Xlsx/Rels.php index 79841404..a67d3ef8 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Rels.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Rels.php @@ -291,7 +291,7 @@ class Rels extends WriterPart /** * Write drawing relationships to XML format. * - * @param int &$chartRef Chart ID + * @param int $chartRef Chart ID * @param bool $includeCharts Flag indicating if we should write charts * * @return string XML Output @@ -425,9 +425,7 @@ class Rels extends WriterPart } /** - * @param $objWriter * @param \PhpOffice\PhpSpreadsheet\Worksheet\Drawing $drawing - * @param $i * * @return int */ diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Theme.php b/src/PhpSpreadsheet/Writer/Xlsx/Theme.php index 3a47be7f..dfde302c 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Theme.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Theme.php @@ -784,13 +784,9 @@ class Theme extends WriterPart /** * Write fonts to XML format. * - * @param XMLWriter $objWriter - * @param string $latinFont - * @param array of string $fontSet - * - * @return string XML Output + * @param string[] $fontSet */ - private function writeFonts($objWriter, $latinFont, $fontSet) + private function writeFonts(XMLWriter $objWriter, string $latinFont, array $fontSet): void { // a:latin $objWriter->startElement('a:latin'); @@ -817,12 +813,8 @@ class Theme extends WriterPart /** * Write colour scheme to XML format. - * - * @param XMLWriter $objWriter - * - * @return string XML Output */ - private function writeColourScheme($objWriter) + private function writeColourScheme(XMLWriter $objWriter): void { foreach (self::$colourScheme as $colourName => $colourValue) { $objWriter->startElement('a:' . $colourName); diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php index 7ad859ac..3978eb6f 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php @@ -1084,7 +1084,7 @@ class Worksheet extends WriterPart private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, array $pStringTable): void { // Flipped stringtable, for faster index searching - $aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->flipStringTable($pStringTable); + $aFlippedStringTable = $this->getParentWriter()->getWriterPartstringtable()->flipStringTable($pStringTable); // sheetData $objWriter->startElement('sheetData'); @@ -1169,7 +1169,7 @@ class Worksheet extends WriterPart $objWriter->writeElement('t', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue))); } elseif ($cellValue instanceof RichText) { $objWriter->startElement('is'); - $this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $cellValue); + $this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $cellValue); $objWriter->endElement(); } } diff --git a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php index e71e3ad2..a524a15c 100644 --- a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php @@ -262,9 +262,6 @@ class AdvancedValueBinderTest extends TestCase /** * @dataProvider stringProvider - * - * @param mixed $value - * @param mixed $wrapped */ public function testStringWrapping(string $value, bool $wrapped): void { diff --git a/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php b/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php index 159af3b9..9225b818 100644 --- a/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php @@ -96,6 +96,20 @@ class CoordinateTest extends TestCase return require 'tests/data/CellCoordinates.php'; } + /** + * @dataProvider providerIndexesFromString + */ + public function testIndexesFromString(array $expectedResult, string $rangeSet): void + { + $result = Coordinate::indexesFromString($rangeSet); + self::assertSame($expectedResult, $result); + } + + public function providerIndexesFromString(): array + { + return require 'tests/data/Cell/IndexesFromString.php'; + } + public function testCoordinateFromStringWithRangeAddress(): void { $cellAddress = 'A1:AI2012'; diff --git a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php index ef22e033..d85de161 100644 --- a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php @@ -8,6 +8,7 @@ use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder; use PhpOffice\PhpSpreadsheet\RichText\RichText; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class DefaultValueBinderTest extends TestCase @@ -15,7 +16,7 @@ class DefaultValueBinderTest extends TestCase private function createCellStub() { // Create a stub for the Cell class. - /** @var Cell $cellStub */ + /** @var Cell&MockObject $cellStub */ $cellStub = $this->getMockBuilder(Cell::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/PhpSpreadsheetTests/DefinedNameTest.php b/tests/PhpSpreadsheetTests/DefinedNameTest.php index 8a411775..4d877e6f 100644 --- a/tests/PhpSpreadsheetTests/DefinedNameTest.php +++ b/tests/PhpSpreadsheetTests/DefinedNameTest.php @@ -135,6 +135,7 @@ class DefinedNameTest extends TestCase DefinedName::createInstance('xyz', $this->spreadsheet->getActiveSheet(), 'A1') ); + /** @var NamedRange $namedRange */ $namedRange = $this->spreadsheet->getDefinedName('XYZ'); self::assertInstanceOf(NamedRange::class, $namedRange); self::assertEquals('A1', $namedRange->getRange()); diff --git a/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php b/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php index 5cd0aec7..045cdcd5 100644 --- a/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php @@ -15,8 +15,6 @@ class ColumnWidthTest extends AbstractFunctional /** * @dataProvider providerFormats - * - * @param $format */ public function testReadColumnWidth($format): void { diff --git a/tests/PhpSpreadsheetTests/Functional/CommentsTest.php b/tests/PhpSpreadsheetTests/Functional/CommentsTest.php index 5ba4e7c8..2b08c9a6 100644 --- a/tests/PhpSpreadsheetTests/Functional/CommentsTest.php +++ b/tests/PhpSpreadsheetTests/Functional/CommentsTest.php @@ -21,8 +21,6 @@ class CommentsTest extends AbstractFunctional * count of comments in correct coords. * * @dataProvider providerFormats - * - * @param $format */ public function testComments($format): void { diff --git a/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php b/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php index 3a417791..176e3b75 100644 --- a/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php +++ b/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php @@ -23,8 +23,8 @@ class CsvContiguousTest extends TestCase // Tell the Reader that we want to use the Read Filter that we've Instantiated // and that we want to store it in contiguous rows/columns self::assertFalse($reader->getContiguous()); - $reader->setReadFilter($chunkFilter) - ->setContiguous(true); + $reader->setReadFilter($chunkFilter); + $reader->setContiguous(true); // Instantiate a new PhpSpreadsheet object manually $spreadsheet = new Spreadsheet(); @@ -65,8 +65,8 @@ class CsvContiguousTest extends TestCase // Tell the Reader that we want to use the Read Filter that we've Instantiated // and that we want to store it in contiguous rows/columns - $reader->setReadFilter($chunkFilter) - ->setContiguous(true); + $reader->setReadFilter($chunkFilter); + $reader->setContiguous(true); // Instantiate a new PhpSpreadsheet object manually $spreadsheet = new Spreadsheet(); diff --git a/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php b/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php index c32c5743..c434aa60 100644 --- a/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php @@ -23,7 +23,6 @@ class XmlScannerTest extends TestCase * * @param mixed $filename * @param mixed $expectedResult - * @param $libxmlDisableEntityLoader */ public function testValidXML($filename, $expectedResult, $libxmlDisableEntityLoader): void { @@ -59,7 +58,6 @@ class XmlScannerTest extends TestCase * @dataProvider providerInvalidXML * * @param mixed $filename - * @param $libxmlDisableEntityLoader */ public function testInvalidXML($filename, $libxmlDisableEntityLoader): void { diff --git a/tests/PhpSpreadsheetTests/Reader/XlsxTest.php b/tests/PhpSpreadsheetTests/Reader/XlsxTest.php index cb84a3b7..1e240283 100644 --- a/tests/PhpSpreadsheetTests/Reader/XlsxTest.php +++ b/tests/PhpSpreadsheetTests/Reader/XlsxTest.php @@ -250,7 +250,6 @@ class XlsxTest extends TestCase * Test if all whitespace is removed from a style definition string. * This is needed to parse it into properties with the correct keys. * - * @param $string * @dataProvider providerStripsWhiteSpaceFromStyleString */ public function testStripsWhiteSpaceFromStyleString($string): void diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php index 2b66c7b4..d53135f9 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php @@ -10,8 +10,6 @@ class XmlTest extends TestCase { /** * @dataProvider providerInvalidSimpleXML - * - * @param $filename */ public function testInvalidSimpleXML($filename): void { diff --git a/tests/PhpSpreadsheetTests/SpreadsheetTest.php b/tests/PhpSpreadsheetTests/SpreadsheetTest.php index 129bea7c..cf293001 100644 --- a/tests/PhpSpreadsheetTests/SpreadsheetTest.php +++ b/tests/PhpSpreadsheetTests/SpreadsheetTest.php @@ -44,9 +44,6 @@ class SpreadsheetTest extends TestCase } /** - * @param $index - * @param $sheetName - * * @dataProvider dataProviderForSheetNames */ public function testGetSheetByName($index, $sheetName): void diff --git a/tests/data/Cell/IndexesFromString.php b/tests/data/Cell/IndexesFromString.php new file mode 100644 index 00000000..c2fe1c09 --- /dev/null +++ b/tests/data/Cell/IndexesFromString.php @@ -0,0 +1,74 @@ + Date: Mon, 5 Apr 2021 09:18:55 +0900 Subject: [PATCH 157/187] Drop obsolete code --- src/PhpSpreadsheet/Writer/Ods.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/PhpSpreadsheet/Writer/Ods.php b/src/PhpSpreadsheet/Writer/Ods.php index f2d535ac..f07ade9a 100644 --- a/src/PhpSpreadsheet/Writer/Ods.php +++ b/src/PhpSpreadsheet/Writer/Ods.php @@ -17,13 +17,6 @@ use ZipStream\ZipStream; class Ods extends BaseWriter { - /** - * Private writer parts. - * - * @var Ods\WriterPart[] - */ - private $writerParts = []; - /** * Private PhpSpreadsheet. * From 59de56bb62fde390cf52cef69ffab336a84d0850 Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Mon, 5 Apr 2021 12:18:11 +0530 Subject: [PATCH 158/187] Move original file to temporary file --- .../Writer/Xlsx/DrawingsTest.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index 0880bde9..c48c86db 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -5,6 +5,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx; use PhpOffice\PhpSpreadsheet\IOFactory; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Settings; +use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; class DrawingsTest extends AbstractFunctional @@ -50,17 +51,24 @@ class DrawingsTest extends AbstractFunctional public function testSaveLoadWithDrawingWithSamePath(): void { // Read spreadsheet from file - $filePath = 'tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx'; + $originalFilePath = 'tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx'; + + $originalFile = file_get_contents($originalFilePath); + + $tempFilePath = File::sysGetTempDir() . '/saving_drawing_with_same_path'; + + file_put_contents($tempFilePath, $originalFile); + $reader = new Xlsx(); - $spreadsheet = $reader->load($filePath); + $spreadsheet = $reader->load($tempFilePath); $spreadsheet->getActiveSheet()->setCellValue('D5', 'foo'); // Save spreadsheet to file to the same path. Success test case won't // throw exception here $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); - $writer->save($filePath); + $writer->save($tempFilePath); - $reloadedSpreadsheet = $reader->load($filePath); + $reloadedSpreadsheet = $reader->load($tempFilePath); // Fake assert. The only thing we need is to ensure the file is loaded without exception self::assertNotNull($reloadedSpreadsheet); From 95b8c4d59bac92d76a3768fde639967d0fe620be Mon Sep 17 00:00:00 2001 From: oleibman Date: Mon, 5 Apr 2021 07:39:03 -0700 Subject: [PATCH 159/187] Continue MathTrig Breakup - Completion! (#1985) * Continue MathTrig Breakup - Completion! Continuing the process of breaking MathTrip.php up into smaller classes. This round takes care of everything that was left: - ABS - DEGREES - EXP - RADIANS - SQRT - SQRTPI - SUMSQ, SUMX2MY2, SUMX2PY2, SUMXMY2 The only notable logic change was that the 3 SUMX* functions had accepted arrays of unlike length; in that condition, they now return N/A, as Excel does. There had been no tests for this condition. All the functions in MathTrig.php are now deprecated. Except for COMBIN, the test suite executes them only from MathTrig MovedFunctionsTest. COMBIN is still directly called by some Statistics Binomial functions which have not yet had the opportunity to be re-coded for the new location. Co-authored-by: Mark Baker --- .../Calculation/Calculation.php | 24 +-- src/PhpSpreadsheet/Calculation/DateTime.php | 8 +- .../Calculation/DateTimeExcel/Helpers.php | 16 -- src/PhpSpreadsheet/Calculation/MathTrig.php | 140 +++++------------ .../Calculation/MathTrig/Absolute.php | 28 ++++ .../Calculation/MathTrig/Degrees.php | 28 ++++ .../Calculation/MathTrig/Exp.php | 28 ++++ .../Calculation/MathTrig/Radians.php | 28 ++++ .../Calculation/MathTrig/Sqrt.php | 28 ++++ .../Calculation/MathTrig/SqrtPi.php | 29 ++++ .../Calculation/MathTrig/SumSquares.php | 142 ++++++++++++++++++ .../Style/NumberFormat/FractionFormatter.php | 2 +- .../Functions/MathTrig/AbsTest.php | 27 ++-- .../Functions/MathTrig/AllSetupTeardown.php | 15 ++ .../Functions/MathTrig/DegreesTest.php | 27 ++-- .../Functions/MathTrig/ExpTest.php | 31 ++-- .../Functions/MathTrig/MInverseTest.php | 4 +- .../Functions/MathTrig/MMultTest.php | 2 +- .../Functions/MathTrig/MovedFunctionsTest.php | 19 +++ .../Functions/MathTrig/RadiansTest.php | 27 ++-- .../Functions/MathTrig/SqrtPiTest.php | 27 ++-- .../Functions/MathTrig/SqrtTest.php | 25 ++- .../Functions/MathTrig/SumIfsTest.php | 13 +- .../Functions/MathTrig/SumSqTest.php | 25 +-- .../Functions/MathTrig/SumX2MY2Test.php | 30 ++-- .../Functions/MathTrig/SumX2PY2Test.php | 30 ++-- .../Functions/MathTrig/SumXMY2Test.php | 30 ++-- tests/data/Calculation/MathTrig/ABS.php | 16 +- tests/data/Calculation/MathTrig/DEGREES.php | 9 +- tests/data/Calculation/MathTrig/EXP.php | 10 +- tests/data/Calculation/MathTrig/RADIANS.php | 11 +- tests/data/Calculation/MathTrig/SQRT.php | 10 +- tests/data/Calculation/MathTrig/SQRTPI.php | 4 + tests/data/Calculation/MathTrig/SUMSQ.php | 9 ++ tests/data/Calculation/MathTrig/SUMX2MY2.php | 10 ++ tests/data/Calculation/MathTrig/SUMX2PY2.php | 10 ++ tests/data/Calculation/MathTrig/SUMXMY2.php | 10 ++ 37 files changed, 634 insertions(+), 298 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Absolute.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Degrees.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Exp.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Radians.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/Sqrt.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/SqrtPi.php create mode 100644 src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 1699b5a0..1df103ca 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -228,7 +228,7 @@ class Calculation private static $phpSpreadsheetFunctions = [ 'ABS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinABS'], + 'functionCall' => [MathTrig\Absolute::class, 'evaluate'], 'argumentCount' => '1', ], 'ACCRINT' => [ @@ -835,7 +835,7 @@ class Calculation ], 'DEGREES' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinDEGREES'], + 'functionCall' => [MathTrig\Degrees::class, 'evaluate'], 'argumentCount' => '1', ], 'DELTA' => [ @@ -975,7 +975,7 @@ class Calculation ], 'EXP' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinEXP'], + 'functionCall' => [MathTrig\Exp::class, 'evaluate'], 'argumentCount' => '1', ], 'EXPONDIST' => [ @@ -2038,7 +2038,7 @@ class Calculation ], 'RADIANS' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinRADIANS'], + 'functionCall' => [MathTrig\Radians::class, 'evaluate'], 'argumentCount' => '1', ], 'RAND' => [ @@ -2185,7 +2185,7 @@ class Calculation ], 'SERIESSUM' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SERIESSUM'], + 'functionCall' => [MathTrig\SeriesSum::class, 'funcSeriesSum'], 'argumentCount' => '4', ], 'SHEET' => [ @@ -2205,7 +2205,7 @@ class Calculation ], 'SIN' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinSIN'], + 'functionCall' => [MathTrig\Sin::class, 'funcSin'], 'argumentCount' => '1', ], 'SINH' => [ @@ -2250,12 +2250,12 @@ class Calculation ], 'SQRT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'builtinSQRT'], + 'functionCall' => [MathTrig\Sqrt::class, 'evaluate'], 'argumentCount' => '1', ], 'SQRTPI' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SQRTPI'], + 'functionCall' => [MathTrig\SqrtPi::class, 'evaluate'], 'argumentCount' => '1', ], 'STANDARDIZE' => [ @@ -2331,22 +2331,22 @@ class Calculation ], 'SUMSQ' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMSQ'], + 'functionCall' => [MathTrig\SumSquares::class, 'sumSquare'], 'argumentCount' => '1+', ], 'SUMX2MY2' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMX2MY2'], + 'functionCall' => [MathTrig\SumSquares::class, 'sumXSquaredMinusYSquared'], 'argumentCount' => '2', ], 'SUMX2PY2' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMX2PY2'], + 'functionCall' => [MathTrig\SumSquares::class, 'sumXSquaredPlusYSquared'], 'argumentCount' => '2', ], 'SUMXMY2' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig::class, 'SUMXMY2'], + 'functionCall' => [MathTrig\SumSquares::class, 'sumXMinusYSquared'], 'argumentCount' => '2', ], 'SWITCH' => [ diff --git a/src/PhpSpreadsheet/Calculation/DateTime.php b/src/PhpSpreadsheet/Calculation/DateTime.php index 3b79a6d6..7643ed0b 100644 --- a/src/PhpSpreadsheet/Calculation/DateTime.php +++ b/src/PhpSpreadsheet/Calculation/DateTime.php @@ -23,7 +23,7 @@ class DateTime /** * getDateValue. * - * @Deprecated 2.0.0 Use the method getDateValueNoThrow in the DateTimeExcel\Helpers class instead + * @Deprecated 2.0.0 Use the method getDateValue in the DateTimeExcel\Helpers class instead * * @param mixed $dateValue * @@ -31,7 +31,11 @@ class DateTime */ public static function getDateValue($dateValue) { - return DateTimeExcel\Helpers::getDateValueNoThrow($dateValue); + try { + return DateTimeExcel\Helpers::getDateValue($dateValue); + } catch (Exception $e) { + return $e->getMessage(); + } } /** diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php index 48300642..636f0c87 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php @@ -56,22 +56,6 @@ class Helpers return (float) $dateValue; } - /** - * getDateValueNoThrow. - * - * @param mixed $dateValue - * - * @return mixed Excel date/time serial value, or string if error - */ - public static function getDateValueNoThrow($dateValue) - { - try { - return self::getDateValue($dateValue); - } catch (Exception $e) { - return $e->getMessage(); - } - } - /** * getTimeValue. * diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index e960d7ef..7f30edeb 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -640,23 +640,15 @@ class MathTrig * * Returns the square root of (number * pi). * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\SqrtPi class instead + * * @param float $number Number * * @return float|string Square Root of Number * Pi, or a string containing an error */ public static function SQRTPI($number) { - $number = Functions::flattenSingleValue($number); - - if (is_numeric($number)) { - if ($number < 0) { - return Functions::NAN(); - } - - return sqrt($number * M_PI); - } - - return Functions::VALUE(); + return MathTrig\SqrtPi::evaluate($number); } /** @@ -769,107 +761,63 @@ class MathTrig * * SUMSQ returns the sum of the squares of the arguments * + * @Deprecated 2.0.0 Use the sumSquare method in the MathTrig\SumSquares class instead + * * Excel Function: * SUMSQ(value1[,value2[, ...]]) * * @param mixed ...$args Data values * - * @return float + * @return float|string */ public static function SUMSQ(...$args) { - $returnValue = 0; - - // Loop through arguments - foreach (Functions::flattenArray($args) as $arg) { - // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { - $returnValue += ($arg * $arg); - } - } - - return $returnValue; + return MathTrig\SumSquares::sumSquare(...$args); } /** * SUMX2MY2. * + * @Deprecated 2.0.0 Use the sumXSquaredMinusYSquared method in the MathTrig\SumSquares class instead + * * @param mixed[] $matrixData1 Matrix #1 * @param mixed[] $matrixData2 Matrix #2 * - * @return float + * @return float|string */ public static function SUMX2MY2($matrixData1, $matrixData2) { - $array1 = Functions::flattenArray($matrixData1); - $array2 = Functions::flattenArray($matrixData2); - $count = min(count($array1), count($array2)); - - $result = 0; - for ($i = 0; $i < $count; ++$i) { - if ( - ((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && - ((is_numeric($array2[$i])) && (!is_string($array2[$i]))) - ) { - $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]); - } - } - - return $result; + return MathTrig\SumSquares::sumXSquaredMinusYSquared($matrixData1, $matrixData2); } /** * SUMX2PY2. * + * @Deprecated 2.0.0 Use the sumXSquaredPlusYSquared method in the MathTrig\SumSquares class instead + * * @param mixed[] $matrixData1 Matrix #1 * @param mixed[] $matrixData2 Matrix #2 * - * @return float + * @return float|string */ public static function SUMX2PY2($matrixData1, $matrixData2) { - $array1 = Functions::flattenArray($matrixData1); - $array2 = Functions::flattenArray($matrixData2); - $count = min(count($array1), count($array2)); - - $result = 0; - for ($i = 0; $i < $count; ++$i) { - if ( - ((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && - ((is_numeric($array2[$i])) && (!is_string($array2[$i]))) - ) { - $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]); - } - } - - return $result; + return MathTrig\SumSquares::sumXSquaredPlusYSquared($matrixData1, $matrixData2); } /** * SUMXMY2. * + * @Deprecated 2.0.0 Use the sumXMinusYSquared method in the MathTrig\SumSquares class instead + * * @param mixed[] $matrixData1 Matrix #1 * @param mixed[] $matrixData2 Matrix #2 * - * @return float + * @return float|string */ public static function SUMXMY2($matrixData1, $matrixData2) { - $array1 = Functions::flattenArray($matrixData1); - $array2 = Functions::flattenArray($matrixData2); - $count = min(count($array1), count($array2)); - - $result = 0; - for ($i = 0; $i < $count; ++$i) { - if ( - ((is_numeric($array1[$i])) && (!is_string($array1[$i]))) && - ((is_numeric($array2[$i])) && (!is_string($array2[$i]))) - ) { - $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]); - } - } - - return $result; + return MathTrig\SumSquares::sumXMinusYSquared($matrixData1, $matrixData2); } /** @@ -1057,19 +1005,15 @@ class MathTrig * * Returns the result of builtin function abs after validating args. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Absolute class instead + * * @param mixed $number Should be numeric * * @return float|int|string Rounded number */ public static function builtinABS($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return abs($number); + return MathTrig\Absolute::evaluate($number); } /** @@ -1205,19 +1149,15 @@ class MathTrig * * Returns the result of builtin function rad2deg after validating args. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Degrees class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinDEGREES($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return rad2deg($number); + return MathTrig\Degrees::evaluate($number); } /** @@ -1225,19 +1165,15 @@ class MathTrig * * Returns the result of builtin function exp after validating args. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Exp class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinEXP($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return exp($number); + return MathTrig\Exp::evaluate($number); } /** @@ -1277,19 +1213,15 @@ class MathTrig * * Returns the result of builtin function deg2rad after validating args. * + * @Deprecated 2.0.0 Use the funcSin method in the MathTrig\Sin class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinRADIANS($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return deg2rad($number); + return MathTrig\Radians::evaluate($number); } /** @@ -1329,19 +1261,15 @@ class MathTrig * * Returns the result of builtin function sqrt after validating args. * + * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Sqrt class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number */ public static function builtinSQRT($number) { - $number = Functions::flattenSingleValue($number); - - if (!is_numeric($number)) { - return Functions::VALUE(); - } - - return self::numberOrNan(sqrt($number)); + return MathTrig\Sqrt::evaluate($number); } /** diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Absolute.php b/src/PhpSpreadsheet/Calculation/MathTrig/Absolute.php new file mode 100644 index 00000000..c2dc579f --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Absolute.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return abs($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Degrees.php b/src/PhpSpreadsheet/Calculation/MathTrig/Degrees.php new file mode 100644 index 00000000..501817be --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Degrees.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return rad2deg($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Exp.php b/src/PhpSpreadsheet/Calculation/MathTrig/Exp.php new file mode 100644 index 00000000..f3f8af59 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Exp.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return exp($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Radians.php b/src/PhpSpreadsheet/Calculation/MathTrig/Radians.php new file mode 100644 index 00000000..15e97011 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Radians.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return deg2rad($number); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Sqrt.php b/src/PhpSpreadsheet/Calculation/MathTrig/Sqrt.php new file mode 100644 index 00000000..aeb38234 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Sqrt.php @@ -0,0 +1,28 @@ +getMessage(); + } + + return Helpers::numberOrNan(sqrt($number)); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/SqrtPi.php b/src/PhpSpreadsheet/Calculation/MathTrig/SqrtPi.php new file mode 100644 index 00000000..6ff79203 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/SqrtPi.php @@ -0,0 +1,29 @@ +getMessage(); + } + + return sqrt($number * M_PI); + } +} diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php b/src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php new file mode 100644 index 00000000..a750b149 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php @@ -0,0 +1,142 @@ +getMessage(); + } + + return $returnValue; + } + + private static function getCount(array $array1, array $array2): int + { + $count = count($array1); + if ($count !== count($array2)) { + throw new Exception(Functions::NA()); + } + + return $count; + } + + /** + * These functions accept only numeric arguments, not even strings which are numeric. + * + * @param mixed $item + */ + private static function numericNotString($item): bool + { + return is_numeric($item) && !is_string($item); + } + + /** + * SUMX2MY2. + * + * @param mixed[] $matrixData1 Matrix #1 + * @param mixed[] $matrixData2 Matrix #2 + * + * @return float|string + */ + public static function sumXSquaredMinusYSquared($matrixData1, $matrixData2) + { + try { + $array1 = Functions::flattenArray($matrixData1); + $array2 = Functions::flattenArray($matrixData2); + $count = self::getCount($array1, $array2); + + $result = 0; + for ($i = 0; $i < $count; ++$i) { + if (self::numericNotString($array1[$i]) && self::numericNotString($array2[$i])) { + $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]); + } + } + } catch (Exception $e) { + return $e->getMessage(); + } + + return $result; + } + + /** + * SUMX2PY2. + * + * @param mixed[] $matrixData1 Matrix #1 + * @param mixed[] $matrixData2 Matrix #2 + * + * @return float|string + */ + public static function sumXSquaredPlusYSquared($matrixData1, $matrixData2) + { + try { + $array1 = Functions::flattenArray($matrixData1); + $array2 = Functions::flattenArray($matrixData2); + $count = self::getCount($array1, $array2); + + $result = 0; + for ($i = 0; $i < $count; ++$i) { + if (self::numericNotString($array1[$i]) && self::numericNotString($array2[$i])) { + $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]); + } + } + } catch (Exception $e) { + return $e->getMessage(); + } + + return $result; + } + + /** + * SUMXMY2. + * + * @param mixed[] $matrixData1 Matrix #1 + * @param mixed[] $matrixData2 Matrix #2 + * + * @return float|string + */ + public static function sumXMinusYSquared($matrixData1, $matrixData2) + { + try { + $array1 = Functions::flattenArray($matrixData1); + $array2 = Functions::flattenArray($matrixData2); + $count = self::getCount($array1, $array2); + + $result = 0; + for ($i = 0; $i < $count; ++$i) { + if (self::numericNotString($array1[$i]) && self::numericNotString($array2[$i])) { + $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]); + } + } + } catch (Exception $e) { + return $e->getMessage(); + } + + return $result; + } +} diff --git a/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php b/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php index 2b1c7911..48d927f2 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php +++ b/src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php @@ -17,7 +17,7 @@ class FractionFormatter extends BaseFormatter $decimalLength = strlen($decimalPart); $decimalDivisor = 10 ** $decimalLength; - $GCD = MathTrig::GCD($decimalPart, $decimalDivisor); + $GCD = MathTrig\Gcd::evaluate($decimalPart, $decimalDivisor); $adjustedDecimalPart = $decimalPart / $GCD; $adjustedDecimalDivisor = $decimalDivisor / $GCD; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php index 49816024..7e74474a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php @@ -2,31 +2,26 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class AbsTest extends TestCase +class AbsTest extends AllSetupTeardown { /** * @dataProvider providerAbs * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testRound($expectedResult, $val = null): void + public function testRound($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=ABS()'; + $sheet = $this->sheet; + $this->mightHaveException($expectedResult); + $this->setCell('A1', $number); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=ABS()'); } else { - $formula = "=ABS($val)"; + $sheet->getCell('B1')->setValue('=ABS(A1)'); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); - self::assertEqualsWithDelta($expectedResult, $result, 1E-12); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertSame($expectedResult, $result); } public function providerAbs() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php index 86c30c22..eef757f4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; +use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; @@ -49,4 +50,18 @@ class AllSetupTeardown extends TestCase $this->expectException(CalcException::class); } } + + /** + * @param mixed $value + */ + protected function setCell(string $cell, $value): void + { + if ($value !== null) { + if (is_string($value) && is_numeric($value)) { + $this->sheet->getCell($cell)->setValueExplicit($value, DataType::TYPE_STRING); + } else { + $this->sheet->getCell($cell)->setValue($value); + } + } + } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php index 3f92703b..d441a943 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php @@ -2,31 +2,26 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class DegreesTest extends TestCase +class DegreesTest extends AllSetupTeardown { /** * @dataProvider providerDEGREES * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testDEGREES($expectedResult, $val = null): void + public function testDegrees($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=DEGREES()'; + $sheet = $this->sheet; + $this->mightHaveException($expectedResult); + $this->setCell('A1', $number); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=DEGREES()'); } else { - $formula = "=DEGREES($val)"; + $sheet->getCell('B1')->setValue('=DEGREES(A1)'); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); - self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } public function providerDegrees() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php index 89bc0097..7e4510fa 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php @@ -2,31 +2,28 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class ExpTest extends TestCase +class ExpTest extends AllSetupTeardown { /** * @dataProvider providerEXP * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testEXP($expectedResult, $val = null): void + public function testEXP($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=EXP()'; - } else { - $formula = "=EXP($val)"; + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($number !== null) { + $sheet->getCell('A1')->setValue($number); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); - self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=EXP()'); + } else { + $sheet->getCell('B1')->setValue('=EXP(A1)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } public function providerEXP() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php index 8831fe83..1912fe07 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php @@ -11,9 +11,9 @@ class MInverseTest extends AllSetupTeardown * * @param mixed $expectedResult */ - public function testMINVERSE($expectedResult, ...$args): void + public function testMINVERSE($expectedResult, array $args): void { - $result = MathTrig::MINVERSE(...$args); + $result = MathTrig\MatrixFunctions::funcMInverse($args); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php index 6c40103c..5e0d45f5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php @@ -13,7 +13,7 @@ class MMultTest extends AllSetupTeardown */ public function testMMULT($expectedResult, ...$args): void { - $result = MathTrig::MMULT(...$args); + $result = MathTrig\MatrixFunctions::funcMMult(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php index 580092cd..2cca8f36 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MovedFunctionsTest.php @@ -16,6 +16,7 @@ class MovedFunctionsTest extends TestCase { public function testMovedFunctions(): void { + self::assertSame(1, MathTrig::builtinABS(1)); self::assertEqualsWithDelta(0, MathTrig::builtinACOS(1), 1E-9); self::assertEqualsWithDelta(0, MathTrig::builtinACOSH(1), 1E-9); self::assertEqualsWithDelta(3.04192400109863, MathTrig::ACOT(-10), 1E-9); @@ -35,12 +36,15 @@ class MovedFunctionsTest extends TestCase self::assertEquals('#DIV/0!', MathTrig::COTH(0)); self::assertEquals('#DIV/0!', MathTrig::CSC(0)); self::assertEquals('#DIV/0!', MathTrig::CSCH(0)); + self::assertEquals(0, MathTrig::builtinDEGREES(0)); self::assertEquals(6, MathTrig::EVEN(4.5)); + self::assertEquals(1, MathTrig::builtinEXP(0)); self::assertEquals(6, MathTrig::FACT(3)); self::assertEquals(105, MathTrig::FACTDOUBLE(7)); self::assertEquals(-6, MathTrig::FLOOR(-4.5, 2)); self::assertEquals(0.23, MathTrig::FLOORMATH(0.234, 0.01)); self::assertEquals(-4, MathTrig::FLOORPRECISE(-2.5, 2)); + self::assertEquals(2, MathTrig::GCD(4, 6)); self::assertEquals(-9, MathTrig::INT(-8.3)); self::assertEquals(12, MathTrig::LCM(4, 6)); self::assertEqualswithDelta(2.302585, MathTrig::builtinLN(10), 1E-6); @@ -58,10 +62,12 @@ class MovedFunctionsTest extends TestCase self::assertEquals(1, MathTrig::MOD(5, 2)); self::assertEquals(6, MathTrig::MROUND(7.3, 3)); self::assertEquals(1, MathTrig::MULTINOMIAL(1)); + self::assertEquals(0, MathTrig::numberOrNan(0)); self::assertEquals(5, MathTrig::ODD(4.5)); self::assertEquals(8, MathTrig::POWER(2, 3)); self::assertEquals(8, MathTrig::PRODUCT(1, 2, 4)); self::assertEquals(8, MathTrig::QUOTIENT(17, 2)); + self::assertEquals(0, MathTrig::builtinRADIANS(0)); self::assertGreaterThanOrEqual(0, MATHTRIG::RAND()); self::assertEquals('I', MathTrig::ROMAN(1)); self::assertEquals(3.3, MathTrig::builtinROUND(3.27, 1)); @@ -73,10 +79,23 @@ class MovedFunctionsTest extends TestCase self::assertEquals(1, MathTrig::SIGN(79.2)); self::assertEquals(0, MathTrig::builtinSIN(0)); self::assertEquals(0, MathTrig::builtinSINH(0)); + self::assertEquals(0, MathTrig::builtinSQRT(0)); + self::assertEqualswithDelta(3.54490770181103, MathTrig::SQRTPI(4), 1E-6); self::assertEquals(0, MathTrig::SUBTOTAL(2, [0, 0])); self::assertEquals(7, MathTrig::SUM(1, 2, 4)); self::assertEquals(4, MathTrig::SUMIF([[2], [4]], '>2')); + self::assertEquals(2, MathTrig::SUMIFS( + [[1], [1], [1]], + [['Y'], ['Y'], ['N']], + '=Y', + [['H'], ['H'], ['H']], + '=H' + )); self::assertEquals(17, MathTrig::SUMPRODUCT([1, 2, 3], [5, 0, 4])); + self::assertEquals(21, MathTrig::SUMSQ(1, 2, 4)); + self::assertEquals(-20, MathTrig::SUMX2MY2([1, 2], [3, 4])); + self::assertEquals(30, MathTrig::SUMX2PY2([1, 2], [3, 4])); + self::assertEquals(8, MathTrig::SUMXMY2([1, 2], [3, 4])); self::assertEquals(0, MathTrig::builtinTAN(0)); self::assertEquals(0, MathTrig::builtinTANH(0)); self::assertEquals(70, MathTrig::TRUNC(79.2, -1)); diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php index b5849540..00af620e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php @@ -2,31 +2,26 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class RadiansTest extends TestCase +class RadiansTest extends AllSetupTeardown { /** * @dataProvider providerRADIANS * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testRADIANS($expectedResult, $val = null): void + public function testRADIANS($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=RADIANS()'; + $sheet = $this->sheet; + $this->mightHaveException($expectedResult); + $this->setCell('A1', $number); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=RADIANS()'); } else { - $formula = "=RADIANS($val)"; + $sheet->getCell('B1')->setValue('=RADIANS(A1)'); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); - self::assertEqualsWithDelta($expectedResult, $result, 1E-6); + $result = $sheet->getCell('B1')->getCalculatedValue(); + self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } public function providerRADIANS() diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php index c49934ea..fe130d8c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php @@ -2,26 +2,27 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class SqrtPiTest extends TestCase +class SqrtPiTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSQRTPI * * @param mixed $expectedResult - * @param mixed $value + * @param mixed $number */ - public function testSQRTPI($expectedResult, $value): void + public function testSQRTPI($expectedResult, $number): void { - $result = MathTrig::SQRTPI($value); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + if ($number !== null) { + $sheet->getCell('A1')->setValue($number); + } + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=SQRTPI()'); + } else { + $sheet->getCell('B1')->setValue('=SQRTPI(A1)'); + } + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php index 972035e7..9e82fe70 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php @@ -2,30 +2,25 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PHPUnit\Framework\TestCase; - -class SqrtTest extends TestCase +class SqrtTest extends AllSetupTeardown { /** * @dataProvider providerSQRT * * @param mixed $expectedResult - * @param mixed $val + * @param mixed $number */ - public function testSQRT($expectedResult, $val = null): void + public function testSQRT($expectedResult, $number = 'omitted'): void { - if ($val === null) { - $this->expectException(CalcExp::class); - $formula = '=SQRT()'; + $sheet = $this->sheet; + $this->mightHaveException($expectedResult); + $this->setCell('A1', $number); + if ($number === 'omitted') { + $sheet->getCell('B1')->setValue('=SQRT()'); } else { - $formula = "=SQRT($val)"; + $sheet->getCell('B1')->setValue('=SQRT(A1)'); } - $spreadsheet = new Spreadsheet(); - $sheet = $spreadsheet->getActiveSheet(); - $sheet->getCell('A1')->setValue($formula); - $result = $sheet->getCell('A1')->getCalculatedValue(); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php index b7be17c9..a4a99888 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php @@ -2,17 +2,10 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; +use PhpOffice\PhpSpreadsheet\Calculation\Statistical; -class SumIfsTest extends TestCase +class SumIfsTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMIFS * @@ -20,7 +13,7 @@ class SumIfsTest extends TestCase */ public function testSUMIFS($expectedResult, ...$args): void { - $result = MathTrig::SUMIFS(...$args); + $result = Statistical\Conditional::SUMIFS(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php index f1165e7b..e811dd75 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php @@ -2,17 +2,8 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; -use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; - -class SumSqTest extends TestCase +class SumSqTest extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMSQ * @@ -20,7 +11,19 @@ class SumSqTest extends TestCase */ public function testSUMSQ($expectedResult, ...$args): void { - $result = MathTrig::SUMSQ(...$args); + $this->mightHaveException($expectedResult); + $maxRow = 0; + $funcArg = ''; + $sheet = $this->sheet; + foreach ($args as $arg) { + ++$maxRow; + $funcArg = "A1:A$maxRow"; + if ($arg !== null) { + $sheet->getCell("A$maxRow")->setValue($arg); + } + } + $sheet->getCell('B1')->setValue("=SUMSQ($funcArg)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php index 3bf2785b..a6813bb2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php @@ -3,24 +3,34 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class SumX2MY2Test extends TestCase +class SumX2MY2Test extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMX2MY2 * * @param mixed $expectedResult */ - public function testSUMX2MY2($expectedResult, ...$args): void + public function testSUMX2MY2($expectedResult, array $matrixData1, array $matrixData2): void { - $result = MathTrig::SUMX2MY2(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $maxRow = 0; + $funcArg1 = ''; + foreach (Functions::flattenArray($matrixData1) as $arg) { + ++$maxRow; + $funcArg1 = "A1:A$maxRow"; + $this->setCell("A$maxRow", $arg); + } + $maxRow = 0; + $funcArg2 = ''; + foreach (Functions::flattenArray($matrixData2) as $arg) { + ++$maxRow; + $funcArg2 = "C1:C$maxRow"; + $this->setCell("C$maxRow", $arg); + } + $sheet->getCell('B1')->setValue("=SUMX2MY2($funcArg1, $funcArg2)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php index a370d79b..2db78440 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php @@ -3,24 +3,34 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class SumX2PY2Test extends TestCase +class SumX2PY2Test extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMX2PY2 * * @param mixed $expectedResult */ - public function testSUMX2PY2($expectedResult, ...$args): void + public function testSUMX2PY2($expectedResult, array $matrixData1, array $matrixData2): void { - $result = MathTrig::SUMX2PY2(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $maxRow = 0; + $funcArg1 = ''; + foreach (Functions::flattenArray($matrixData1) as $arg) { + ++$maxRow; + $funcArg1 = "A1:A$maxRow"; + $this->setCell("A$maxRow", $arg); + } + $maxRow = 0; + $funcArg2 = ''; + foreach (Functions::flattenArray($matrixData2) as $arg) { + ++$maxRow; + $funcArg2 = "C1:C$maxRow"; + $this->setCell("C$maxRow", $arg); + } + $sheet->getCell('B1')->setValue("=SUMX2PY2($funcArg1, $funcArg2)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php index 1f64523b..eaa1ec7a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php @@ -3,24 +3,34 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\MathTrig; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; -use PHPUnit\Framework\TestCase; -class SumXMY2Test extends TestCase +class SumXMY2Test extends AllSetupTeardown { - protected function setUp(): void - { - Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL); - } - /** * @dataProvider providerSUMXMY2 * * @param mixed $expectedResult */ - public function testSUMXMY2($expectedResult, ...$args): void + public function testSUMXMY2($expectedResult, array $matrixData1, array $matrixData2): void { - $result = MathTrig::SUMXMY2(...$args); + $this->mightHaveException($expectedResult); + $sheet = $this->sheet; + $maxRow = 0; + $funcArg1 = ''; + foreach (Functions::flattenArray($matrixData1) as $arg) { + ++$maxRow; + $funcArg1 = "A1:A$maxRow"; + $this->setCell("A$maxRow", $arg); + } + $maxRow = 0; + $funcArg2 = ''; + foreach (Functions::flattenArray($matrixData2) as $arg) { + ++$maxRow; + $funcArg2 = "C1:C$maxRow"; + $this->setCell("C$maxRow", $arg); + } + $sheet->getCell('B1')->setValue("=SUMXMY2($funcArg1, $funcArg2)"); + $result = $sheet->getCell('B1')->getCalculatedValue(); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } diff --git a/tests/data/Calculation/MathTrig/ABS.php b/tests/data/Calculation/MathTrig/ABS.php index 2fc9631b..4082ceeb 100644 --- a/tests/data/Calculation/MathTrig/ABS.php +++ b/tests/data/Calculation/MathTrig/ABS.php @@ -1,12 +1,18 @@ Date: Tue, 6 Apr 2021 01:22:22 +0900 Subject: [PATCH 160/187] Update reading-and-writing-to-file.md --- docs/topics/reading-and-writing-to-file.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/topics/reading-and-writing-to-file.md b/docs/topics/reading-and-writing-to-file.md index e1b7e3a2..4b00a453 100644 --- a/docs/topics/reading-and-writing-to-file.md +++ b/docs/topics/reading-and-writing-to-file.md @@ -580,6 +580,18 @@ $writer->setUseBOM(true); $writer->save("05featuredemo.csv"); ``` +#### Writeing CSV files with desired encoding + +It can be set to output with the encoding that can be specified by PHP's mb_convert_encoding. +This looks like the following code: + +```php +$writer = new \PhpOffice\PhpSpreadsheet\Writer\Csv($spreadsheet); +$writer->setUseBOM(false); +$writer->setOutputEncoding('SJIS-WIN'); +$writer->save("05featuredemo.csv"); +``` + #### Decimal and thousands separators If the worksheet you are exporting contains numbers with decimal or From 3da51de1a9b60499264ec2b46f738bad0da3a0fc Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 01:26:10 +0900 Subject: [PATCH 161/187] Update reading-and-writing-to-file.md --- docs/topics/reading-and-writing-to-file.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/reading-and-writing-to-file.md b/docs/topics/reading-and-writing-to-file.md index 4b00a453..a9f767aa 100644 --- a/docs/topics/reading-and-writing-to-file.md +++ b/docs/topics/reading-and-writing-to-file.md @@ -580,7 +580,7 @@ $writer->setUseBOM(true); $writer->save("05featuredemo.csv"); ``` -#### Writeing CSV files with desired encoding +#### Writing CSV files with desired encoding It can be set to output with the encoding that can be specified by PHP's mb_convert_encoding. This looks like the following code: From dd9cb259d0cd7b26c733322427794810a97fcc8f Mon Sep 17 00:00:00 2001 From: Vivek Kumar Date: Mon, 5 Apr 2021 22:14:50 +0530 Subject: [PATCH 162/187] Unlink temporary file --- .../Writer/Xlsx/DrawingsTest.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index c48c86db..ef2002b5 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -51,24 +51,26 @@ class DrawingsTest extends AbstractFunctional public function testSaveLoadWithDrawingWithSamePath(): void { // Read spreadsheet from file - $originalFilePath = 'tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx'; + $originalFileName = 'tests/data/Writer/XLSX/saving_drawing_with_same_path.xlsx'; - $originalFile = file_get_contents($originalFilePath); + $originalFile = file_get_contents($originalFileName); - $tempFilePath = File::sysGetTempDir() . '/saving_drawing_with_same_path'; + $tempFileName = File::sysGetTempDir() . '/saving_drawing_with_same_path'; - file_put_contents($tempFilePath, $originalFile); + file_put_contents($tempFileName, $originalFile); $reader = new Xlsx(); - $spreadsheet = $reader->load($tempFilePath); + $spreadsheet = $reader->load($tempFileName); $spreadsheet->getActiveSheet()->setCellValue('D5', 'foo'); // Save spreadsheet to file to the same path. Success test case won't // throw exception here $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); - $writer->save($tempFilePath); + $writer->save($tempFileName); - $reloadedSpreadsheet = $reader->load($tempFilePath); + $reloadedSpreadsheet = $reader->load($tempFileName); + + unlink($tempFileName); // Fake assert. The only thing we need is to ensure the file is loaded without exception self::assertNotNull($reloadedSpreadsheet); From eef90b62df48c15fc537eaba084d1674772f22eb Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 02:05:08 +0900 Subject: [PATCH 163/187] Create CsvOutputEncoding.php --- tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php new file mode 100644 index 00000000..b3d9bbc7 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php @@ -0,0 +1 @@ + Date: Tue, 6 Apr 2021 02:47:46 +0900 Subject: [PATCH 164/187] Delete CsvOutputEncoding.php --- tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php | 1 - 1 file changed, 1 deletion(-) delete mode 100644 tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php deleted file mode 100644 index b3d9bbc7..00000000 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncoding.php +++ /dev/null @@ -1 +0,0 @@ - Date: Tue, 6 Apr 2021 02:56:54 +0900 Subject: [PATCH 165/187] Create CsvOutputEncodingTest.php --- .../Writer/Csv/CsvOutputEncodingTest.php | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php new file mode 100644 index 00000000..9d0c0bb9 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -0,0 +1,35 @@ +getActiveSheet(); + $sheet->setCellValue('A1', 'こんにちは!'); + $sheet->setCellValue('B1', 'Hello!'); + + $filename = File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'; + $writer->useBOM(false); + $writer->setOutputEncoding(''); + $writer->save($filename); + $a = file_get_contents($filename); + unlink($filename); + + $filename = File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'; + $writer->useBOM(false); + $writer->setOutputEncoding('SJIS-win'); + $writer->save($filename); + $b = file_get_contents($filename); + unlink($filename); + + self::assertEquals(mb_convert_encoding($a, 'SJIS-win'), $b); + } +} From 2df8e1a93f6c80baf6b08065b26caeb48b2f2e0a Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 03:07:10 +0900 Subject: [PATCH 166/187] Update CsvOutputEncodingTest.php --- .../PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index 9d0c0bb9..15140a69 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -16,14 +16,14 @@ class CsvWriteTest extends Functional\AbstractFunctional $sheet->setCellValue('A1', 'こんにちは!'); $sheet->setCellValue('B1', 'Hello!'); - $filename = File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'; + $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'); $writer->useBOM(false); $writer->setOutputEncoding(''); $writer->save($filename); $a = file_get_contents($filename); unlink($filename); - $filename = File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'; + $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'); $writer->useBOM(false); $writer->setOutputEncoding('SJIS-win'); $writer->save($filename); From 7681a1093fdd682f387306835991527b3de005ef Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 03:46:10 +0900 Subject: [PATCH 167/187] Update CsvOutputEncodingTest.php --- tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index 15140a69..da24be20 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Csv; +use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Csv as CsvWriter; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; From 2adc44262c4a79220a2d2361d14ea3d99fd524cd Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 03:48:08 +0900 Subject: [PATCH 168/187] Update CsvOutputEncodingTest.php --- tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index da24be20..ca5c7e1a 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -8,7 +8,7 @@ use PhpOffice\PhpSpreadsheet\Writer\Csv as CsvWriter; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; use PhpOffice\PhpSpreadsheetTests\Functional; -class CsvWriteTest extends Functional\AbstractFunctional +class CsvOutputEncodingTest extends Functional\AbstractFunctional { public function testEncoding(): void { From bfd4a659a4859fb0cde1f1d20319942c7f763d10 Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 04:11:46 +0900 Subject: [PATCH 169/187] Update CsvOutputEncodingTest.php --- .../Writer/Csv/CsvOutputEncodingTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index ca5c7e1a..b2bacbf2 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -17,15 +17,17 @@ class CsvOutputEncodingTest extends Functional\AbstractFunctional $sheet->setCellValue('A1', 'こんにちは!'); $sheet->setCellValue('B1', 'Hello!'); + $write = new CsvWriter($spreadsheet); + $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'); - $writer->useBOM(false); + $writer->setUseBOM(false); $writer->setOutputEncoding(''); $writer->save($filename); $a = file_get_contents($filename); unlink($filename); $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'); - $writer->useBOM(false); + $writer->setUseBOM(false); $writer->setOutputEncoding('SJIS-win'); $writer->save($filename); $b = file_get_contents($filename); From 86f3bdd59852ac899cfabca5dd97b0a15cdbb159 Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 04:27:14 +0900 Subject: [PATCH 170/187] Update CsvOutputEncodingTest.php --- tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index b2bacbf2..4a2cd188 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -17,7 +17,7 @@ class CsvOutputEncodingTest extends Functional\AbstractFunctional $sheet->setCellValue('A1', 'こんにちは!'); $sheet->setCellValue('B1', 'Hello!'); - $write = new CsvWriter($spreadsheet); + $writer = new CsvWriter($spreadsheet); $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'); $writer->setUseBOM(false); From 991616d1d94ce817dc76dca9198e8b51f75817ae Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 04:39:26 +0900 Subject: [PATCH 172/187] Update CsvOutputEncodingTest.php --- .../Writer/Csv/CsvOutputEncodingTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index 4a2cd188..f13a929b 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -18,21 +18,21 @@ class CsvOutputEncodingTest extends Functional\AbstractFunctional $sheet->setCellValue('B1', 'Hello!'); $writer = new CsvWriter($spreadsheet); - + $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'); $writer->setUseBOM(false); $writer->setOutputEncoding(''); $writer->save($filename); $a = file_get_contents($filename); unlink($filename); - + $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'); $writer->setUseBOM(false); $writer->setOutputEncoding('SJIS-win'); $writer->save($filename); $b = file_get_contents($filename); unlink($filename); - + self::assertEquals(mb_convert_encoding($a, 'SJIS-win'), $b); } } From e48ffdbe77f7c5375914462a314787f256314a9c Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 04:44:24 +0900 Subject: [PATCH 173/187] Update CsvOutputEncodingTest.php --- tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index f13a929b..c864d963 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -5,7 +5,6 @@ namespace PhpOffice\PhpSpreadsheetTests\Writer\Csv; use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Csv as CsvWriter; -use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; use PhpOffice\PhpSpreadsheetTests\Functional; class CsvOutputEncodingTest extends Functional\AbstractFunctional From 551bbdf30fef762d97c1827af04aab3db99a0f21 Mon Sep 17 00:00:00 2001 From: Akira Taniguchi Date: Tue, 6 Apr 2021 18:53:21 +0900 Subject: [PATCH 174/187] Update CsvOutputEncodingTest.php --- .../Writer/Csv/CsvOutputEncodingTest.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index c864d963..510515c3 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -18,20 +18,14 @@ class CsvOutputEncodingTest extends Functional\AbstractFunctional $writer = new CsvWriter($spreadsheet); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-UTF-8'); - $writer->setUseBOM(false); - $writer->setOutputEncoding(''); - $writer->save($filename); - $a = file_get_contents($filename); - unlink($filename); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'); $writer->setUseBOM(false); $writer->setOutputEncoding('SJIS-win'); $writer->save($filename); - $b = file_get_contents($filename); + $contents = file_get_contents($filename); unlink($filename); - self::assertEquals(mb_convert_encoding($a, 'SJIS-win'), $b); + // self::assertStringContainsString(mb_convert_encoding('こんにちは!', 'SJIS-win'), $contents); + self::assertStringContainsString("\x82\xb1\x82\xf1\x82\xc9\x82\xbf\x82\xcd\x81\x49", $contents); } } From bc18fb7e77f5b5c64c872960910907deaa5cfdf2 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 6 Apr 2021 12:45:37 +0200 Subject: [PATCH 175/187] more extraction of Excel Financial functions (#1989) * More Financial function extracts, this time looking at the Periodic Cashflow functions * Initial extract of Constant Periodic Interest and Payment functions --- .../Calculation/Calculation.php | 32 +- src/PhpSpreadsheet/Calculation/Financial.php | 451 ++++++------------ .../Financial/CashFlow/Constant/Periodic.php | 190 ++++++++ .../CashFlow/Constant/Periodic/Cumulative.php | 136 ++++++ .../CashFlow/Constant/Periodic/Interest.php | 209 ++++++++ .../Periodic/InterestAndPrincipal.php | 42 ++ .../CashFlow/Constant/Periodic/Payments.php | 119 +++++ .../CashFlow/Variable/NonPeriodic.php | 20 +- .../Functions/Financial/PmtTest.php | 34 ++ .../Functions/Financial/PpmtTest.php | 31 ++ tests/data/Calculation/Financial/CUMIPMT.php | 79 ++- tests/data/Calculation/Financial/CUMPRINC.php | 84 +++- tests/data/Calculation/Financial/FV.php | 82 +++- tests/data/Calculation/Financial/IPMT.php | 93 +++- tests/data/Calculation/Financial/ISPMT.php | 70 ++- tests/data/Calculation/Financial/NPER.php | 62 ++- tests/data/Calculation/Financial/PMT.php | 52 ++ tests/data/Calculation/Financial/PPMT.php | 64 +++ tests/data/Calculation/Financial/PV.php | 36 ++ tests/data/Calculation/Financial/RATE.php | 54 +++ 20 files changed, 1530 insertions(+), 410 deletions(-) create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php create mode 100644 tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php create mode 100644 tests/data/Calculation/Financial/PMT.php create mode 100644 tests/data/Calculation/Financial/PPMT.php diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 1df103ca..9477131f 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -745,12 +745,12 @@ class Calculation ], 'CUMIPMT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'CUMIPMT'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Cumulative::class, 'interest'], 'argumentCount' => '6', ], 'CUMPRINC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'CUMPRINC'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Cumulative::class, 'principal'], 'argumentCount' => '6', ], 'DATE' => [ @@ -1137,12 +1137,12 @@ class Calculation ], 'FV' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'FV'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic::class, 'futureValue'], 'argumentCount' => '3-5', ], 'FVSCHEDULE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'FVSCHEDULE'], + 'functionCall' => [Financial\CashFlow\Single::class, 'futureValue'], 'argumentCount' => '2', ], 'GAMMA' => [ @@ -1434,12 +1434,12 @@ class Calculation ], 'IPMT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'IPMT'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Interest::class, 'payment'], 'argumentCount' => '4-6', ], 'IRR' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'IRR'], + 'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 'rate'], 'argumentCount' => '1,2', ], 'ISBLANK' => [ @@ -1506,7 +1506,7 @@ class Calculation ], 'ISPMT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'ISPMT'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Interest::class, 'schedulePayment'], 'argumentCount' => '4', ], 'ISREF' => [ @@ -1691,7 +1691,7 @@ class Calculation ], 'MIRR' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'MIRR'], + 'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 'modifiedRate'], 'argumentCount' => '3', ], 'MMULT' => [ @@ -1826,12 +1826,12 @@ class Calculation ], 'NPER' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'NPER'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic::class, 'periods'], 'argumentCount' => '3-5', ], 'NPV' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'NPV'], + 'functionCall' => [Financial\CashFlow\Variable\Periodic::class, 'presentValue'], 'argumentCount' => '2+', ], 'NUMBERVALUE' => [ @@ -1893,7 +1893,7 @@ class Calculation ], 'PDURATION' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PDURATION'], + 'functionCall' => [Financial\CashFlow\Single::class, 'periods'], 'argumentCount' => '3', ], 'PEARSON' => [ @@ -1958,7 +1958,7 @@ class Calculation ], 'PMT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PMT'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Payments::class, 'annuity'], 'argumentCount' => '3-5', ], 'POISSON' => [ @@ -1978,7 +1978,7 @@ class Calculation ], 'PPMT' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PPMT'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Payments::class, 'interestPayment'], 'argumentCount' => '4-6', ], 'PRICE' => [ @@ -2013,7 +2013,7 @@ class Calculation ], 'PV' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'PV'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic::class, 'presentValue'], 'argumentCount' => '3-5', ], 'QUARTILE' => [ @@ -2073,7 +2073,7 @@ class Calculation ], 'RATE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'RATE'], + 'functionCall' => [Financial\CashFlow\Constant\Periodic\Interest::class, 'rate'], 'argumentCount' => '3-6', ], 'RECEIVED' => [ @@ -2140,7 +2140,7 @@ class Calculation ], 'RRI' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'RRI'], + 'functionCall' => [Financial\CashFlow\Single::class, 'interestRate'], 'argumentCount' => '3', ], 'RSQ' => [ diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index fde1d3da..ebf5cec1 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -16,21 +16,6 @@ class Financial const FINANCIAL_PRECISION = 1.0e-08; - private static function interestAndPrincipal($rate = 0, $per = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) - { - $pmt = self::PMT($rate, $nper, $pv, $fv, $type); - $capital = $pv; - $interest = 0; - $principal = 0; - for ($i = 1; $i <= $per; ++$i) { - $interest = ($type && $i == 1) ? 0 : -$capital * $rate; - $principal = $pmt - $interest; - $capital += $principal; - } - - return [$interest, $principal]; - } - /** * ACCRINT. * @@ -140,7 +125,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the AMORDEGRC() method in the Financial\Amortization class instead + * @see Financial\Amortization::AMORDEGRC() + * Use the AMORDEGRC() method in the Financial\Amortization class instead * * @param float $cost The cost of the asset * @param mixed $purchased Date of the purchase of the asset @@ -174,7 +160,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the AMORLINC() method in the Financial\Amortization class instead + * @see Financial\Amortization::AMORLINC() + * Use the AMORLINC() method in the Financial\Amortization class instead * * @param float $cost The cost of the asset * @param mixed $purchased Date of the purchase of the asset @@ -206,7 +193,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the COUPDAYBS() method in the Financial\Coupons class instead + * @see Financial\Coupons::COUPDAYBS() + * Use the COUPDAYBS() method in the Financial\Coupons class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue @@ -242,7 +230,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the COUPDAYS() method in the Financial\Coupons class instead + * @see Financial\Coupons::COUPDAYS() + * Use the COUPDAYS() method in the Financial\Coupons class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue @@ -278,7 +267,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the COUPDAYSNC() method in the Financial\Coupons class instead + * @see Financial\Coupons::COUPDAYSNC() + * Use the COUPDAYSNC() method in the Financial\Coupons class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue @@ -314,7 +304,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the COUPNCD() method in the Financial\Coupons class instead + * @see Financial\Coupons::COUPNCD() + * Use the COUPNCD() method in the Financial\Coupons class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue @@ -352,7 +343,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the COUPNUM() method in the Financial\Coupons class instead + * @see Financial\Coupons::COUPNUM() + * Use the COUPNUM() method in the Financial\Coupons class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue @@ -388,7 +380,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the COUPPCD() method in the Financial\Coupons class instead + * @see Financial\Coupons::COUPPCD() + * Use the COUPPCD() method in the Financial\Coupons class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue @@ -423,47 +416,26 @@ class Financial * Excel Function: * CUMIPMT(rate,nper,pv,start,end[,type]) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Cumulative::interest() + * Use the interest() method in the Financial\CashFlow\Constant\Periodic\Cumulative class instead + * * @param float $rate The Interest rate * @param int $nper The total number of payment periods * @param float $pv Present Value * @param int $start The first period in the calculation. - * Payment periods are numbered beginning with 1. + * Payment periods are numbered beginning with 1. * @param int $end the last period in the calculation * @param int $type A number 0 or 1 and indicates when payments are due: - * 0 or omitted At the end of the period. - * 1 At the beginning of the period. + * 0 or omitted At the end of the period. + * 1 At the beginning of the period. * * @return float|string */ public static function CUMIPMT($rate, $nper, $pv, $start, $end, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $nper = (int) Functions::flattenSingleValue($nper); - $pv = Functions::flattenSingleValue($pv); - $start = (int) Functions::flattenSingleValue($start); - $end = (int) Functions::flattenSingleValue($end); - $type = (int) Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - if ($start < 1 || $start > $end) { - return Functions::VALUE(); - } - - // Calculate - $interest = 0; - for ($per = $start; $per <= $end; ++$per) { - $ipmt = self::IPMT($rate, $per, $nper, $pv, 0, $type); - if (is_string($ipmt)) { - return $ipmt; - } - - $interest += $ipmt; - } - - return $interest; + return Financial\CashFlow\Constant\Periodic\Cumulative::interest($rate, $nper, $pv, $start, $end, $type); } /** @@ -474,47 +446,26 @@ class Financial * Excel Function: * CUMPRINC(rate,nper,pv,start,end[,type]) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Cumulative::principal() + * Use the principal() method in the Financial\CashFlow\Constant\Periodic\Cumulative class instead + * * @param float $rate The Interest rate * @param int $nper The total number of payment periods * @param float $pv Present Value * @param int $start The first period in the calculation. - * Payment periods are numbered beginning with 1. + * Payment periods are numbered beginning with 1. * @param int $end the last period in the calculation * @param int $type A number 0 or 1 and indicates when payments are due: - * 0 or omitted At the end of the period. - * 1 At the beginning of the period. + * 0 or omitted At the end of the period. + * 1 At the beginning of the period. * * @return float|string */ public static function CUMPRINC($rate, $nper, $pv, $start, $end, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $nper = (int) Functions::flattenSingleValue($nper); - $pv = Functions::flattenSingleValue($pv); - $start = (int) Functions::flattenSingleValue($start); - $end = (int) Functions::flattenSingleValue($end); - $type = (int) Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - if ($start < 1 || $start > $end) { - return Functions::VALUE(); - } - - // Calculate - $principal = 0; - for ($per = $start; $per <= $end; ++$per) { - $ppmt = self::PPMT($rate, $per, $nper, $pv, 0, $type); - if (is_string($ppmt)) { - return $ppmt; - } - - $principal += $ppmt; - } - - return $principal; + return Financial\CashFlow\Constant\Periodic\Cumulative::principal($rate, $nper, $pv, $start, $end, $type); } /** @@ -532,7 +483,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the DB() method in the Financial\Depreciation class instead + * @see Financial\Depreciation::DB() + * Use the DB() method in the Financial\Depreciation class instead * * @param float $cost Initial cost of the asset * @param float $salvage Value at the end of the depreciation. @@ -562,7 +514,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the DDB() method in the Financial\Depreciation class instead + * @see Financial\Depreciation::DDB() + * Use the DDB() method in the Financial\Depreciation class instead * * @param float $cost Initial cost of the asset * @param float $salvage Value at the end of the depreciation. @@ -646,7 +599,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the decimal() method in the Financial\Dollar class instead + * @see Financial\Dollar::decimal() + * Use the decimal() method in the Financial\Dollar class instead * * @param float $fractional_dollar Fractional Dollar * @param int $fraction Fraction @@ -670,7 +624,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the fractional() method in the Financial\Dollar class instead + * @see Financial\Dollar::fractional() + * Use the fractional() method in the Financial\Dollar class instead * * @param float $decimal_dollar Decimal Dollar * @param int $fraction Fraction @@ -693,7 +648,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the effective() method in the Financial\InterestRate class instead + * @see Financial\InterestRate::effective() + * Use the effective() method in the Financial\InterestRate class instead * * @param float $nominalRate Nominal interest rate * @param int $periodsPerYear Number of compounding payments per year @@ -713,6 +669,11 @@ class Financial * Excel Function: * FV(rate,nper,pmt[,pv[,type]]) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic::futureValue() + * Use the futureValue() method in the Financial\CashFlow\Constant\Periodic class instead + * * @param float $rate The interest rate per period * @param int $nper Total number of payment periods in an annuity * @param float $pmt The payment made each period: it cannot change over the @@ -728,23 +689,7 @@ class Financial */ public static function FV($rate = 0, $nper = 0, $pmt = 0, $pv = 0, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $nper = Functions::flattenSingleValue($nper); - $pmt = Functions::flattenSingleValue($pmt); - $pv = Functions::flattenSingleValue($pv); - $type = Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - - // Calculate - if ($rate !== null && $rate != 0) { - return -$pv * (1 + $rate) ** $nper - $pmt * (1 + $rate * $type) * ((1 + $rate) ** $nper - 1) / $rate; - } - - return -$pv - $pmt * $nper; + return Financial\CashFlow\Constant\Periodic::futureValue($rate, $nper, $pmt, $pv, $type); } /** @@ -825,11 +770,17 @@ class Financial /** * IPMT. * - * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate. + * Returns the interest payment for a given period for an investment based on periodic, constant payments + * and a constant interest rate. * * Excel Function: * IPMT(rate,per,nper,pv[,fv][,type]) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Interest::payment() + * Use the payment() method in the Financial\CashFlow\Constant\Periodic class instead + * * @param float $rate Interest rate per period * @param int $per Period for which we want to find the interest * @param int $nper Number of periods @@ -841,25 +792,7 @@ class Financial */ public static function IPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $per = (int) Functions::flattenSingleValue($per); - $nper = (int) Functions::flattenSingleValue($nper); - $pv = Functions::flattenSingleValue($pv); - $fv = Functions::flattenSingleValue($fv); - $type = (int) Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - if ($per <= 0 || $per > $nper) { - return Functions::NAN(); - } - - // Calculate - $interestAndPrincipal = self::interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type); - - return $interestAndPrincipal[0]; + return Financial\CashFlow\Constant\Periodic\Interest::payment($rate, $per, $nper, $pv, $fv, $type); } /** @@ -876,6 +809,9 @@ class Financial * * @Deprecated 1.18.0 * + * @see Financial\CashFlow\Variable\Periodic::rate() + * Use the rate() method in the Financial\CashFlow\Variable\Periodic class instead + * * @param mixed $values An array or a reference to cells that contain numbers for which you want * to calculate the internal rate of return. * Values must contain at least one positive value and one negative value to @@ -883,9 +819,6 @@ class Financial * @param mixed $guess A number that you guess is close to the result of IRR * * @return float|string - * - *@see Financial\CashFlow\Variable\Periodic::rate() - * Use the IRR() method in the Financial\CashFlow\Variable\Periodic class instead */ public static function IRR($values, $guess = 0.1) { @@ -898,7 +831,12 @@ class Financial * Returns the interest payment for an investment based on an interest rate and a constant payment schedule. * * Excel Function: - * =ISPMT(interest_rate, period, number_payments, PV) + * =ISPMT(interest_rate, period, number_payments, pv) + * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Interest::schedulePayment() + * Use the schedulePayment() method in the Financial\CashFlow\Constant\Periodic class instead * * interest_rate is the interest rate for the investment * @@ -906,32 +844,11 @@ class Financial * * number_payments is the number of payments for the annuity * - * PV is the loan amount or present value of the payments + * pv is the loan amount or present value of the payments */ public static function ISPMT(...$args) { - // Return value - $returnValue = 0; - - // Get the parameters - $aArgs = Functions::flattenArray($args); - $interestRate = array_shift($aArgs); - $period = array_shift($aArgs); - $numberPeriods = array_shift($aArgs); - $principleRemaining = array_shift($aArgs); - - // Calculate - $principlePayment = ($principleRemaining * 1.0) / ($numberPeriods * 1.0); - for ($i = 0; $i <= $period; ++$i) { - $returnValue = $interestRate * $principleRemaining * -1; - $principleRemaining -= $principlePayment; - // principle needs to be 0 after the last payment, don't let floating point screw it up - if ($i == $numberPeriods) { - $returnValue = 0; - } - } - - return $returnValue; + return Financial\CashFlow\Constant\Periodic\Interest::schedulePayment(...$args); } /** @@ -946,7 +863,7 @@ class Financial * @Deprecated 1.18.0 * * @see Financial\CashFlow\Variable\Periodic::modifiedRate() - * Use the MIRR() method in the Financial\CashFlow\Variable\Periodic class instead + * Use the modifiedRate() method in the Financial\CashFlow\Variable\Periodic class instead * * @param mixed $values An array or a reference to cells that contain a series of payments and * income occurring at regular intervals. @@ -971,7 +888,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the nominal() method in the Financial\InterestRate class instead + * @see Financial\InterestRate::nominal() + * Use the nominal() method in the Financial\InterestRate class instead * * @param float $effectiveRate Effective interest rate * @param int $periodsPerYear Number of compounding payments per year @@ -988,6 +906,8 @@ class Financial * * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate. * + * @Deprecated 1.18.0 + * * @param float $rate Interest rate per period * @param int $pmt Periodic payment (annuity) * @param float $pv Present Value @@ -995,33 +915,13 @@ class Financial * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period * * @return float|string Result, or a string containing an error + * + *@see Financial\CashFlow\Constant\Periodic::periods() + * Use the periods() method in the Financial\CashFlow\Constant\Periodic class instead */ public static function NPER($rate = 0, $pmt = 0, $pv = 0, $fv = 0, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $pmt = Functions::flattenSingleValue($pmt); - $pv = Functions::flattenSingleValue($pv); - $fv = Functions::flattenSingleValue($fv); - $type = Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - - // Calculate - if ($rate !== null && $rate != 0) { - if ($pmt == 0 && $pv == 0) { - return Functions::NAN(); - } - - return log(($pmt * (1 + $rate * $type) / $rate - $fv) / ($pv + $pmt * (1 + $rate * $type) / $rate)) / log(1 + $rate); - } - if ($pmt == 0) { - return Functions::NAN(); - } - - return (-$pv - $fv) / $pmt; + return Financial\CashFlow\Constant\Periodic::periods($rate, $pmt, $pv, $fv, $type); } /** @@ -1031,10 +931,10 @@ class Financial * * @Deprecated 1.18.0 * - * @return float + * @see Financial\CashFlow\Variable\Periodic::presentValue() + * Use the presentValue() method in the Financial\CashFlow\Variable\Periodic class instead * - *@see Financial\CashFlow\Variable\Periodic::presentValue() - * Use the NPV() method in the Financial\CashFlow\Variable\Periodic class instead + * @return float */ public static function NPV(...$args) { @@ -1067,6 +967,11 @@ class Financial * * Returns the constant payment (annuity) for a cash flow with a constant interest rate. * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Payments::annuity() + * Use the annuity() method in the Financial\CashFlow\Constant\Periodic\Payments class instead + * * @param float $rate Interest rate per period * @param int $nper Number of periods * @param float $pv Present Value @@ -1077,29 +982,19 @@ class Financial */ public static function PMT($rate = 0, $nper = 0, $pv = 0, $fv = 0, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $nper = Functions::flattenSingleValue($nper); - $pv = Functions::flattenSingleValue($pv); - $fv = Functions::flattenSingleValue($fv); - $type = Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - - // Calculate - if ($rate !== null && $rate != 0) { - return (-$fv - $pv * (1 + $rate) ** $nper) / (1 + $rate * $type) / (((1 + $rate) ** $nper - 1) / $rate); - } - - return (-$pv - $fv) / $nper; + return Financial\CashFlow\Constant\Periodic\Payments::annuity($rate, $nper, $pv, $fv, $type); } /** * PPMT. * - * Returns the interest payment for a given period for an investment based on periodic, constant payments and a constant interest rate. + * Returns the interest payment for a given period for an investment based on periodic, constant payments + * and a constant interest rate. + * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Payments::interestPayment() + * Use the interestPayment() method in the Financial\CashFlow\Constant\Periodic\Payments class instead * * @param float $rate Interest rate per period * @param int $per Period for which we want to find the interest @@ -1112,25 +1007,7 @@ class Financial */ public static function PPMT($rate, $per, $nper, $pv, $fv = 0, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $per = (int) Functions::flattenSingleValue($per); - $nper = (int) Functions::flattenSingleValue($nper); - $pv = Functions::flattenSingleValue($pv); - $fv = Functions::flattenSingleValue($fv); - $type = (int) Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - if ($per <= 0 || $per > $nper) { - return Functions::NAN(); - } - - // Calculate - $interestAndPrincipal = self::interestAndPrincipal($rate, $per, $nper, $pv, $fv, $type); - - return $interestAndPrincipal[1]; + return Financial\CashFlow\Constant\Periodic\Payments::interestPayment($rate, $per, $nper, $pv, $fv, $type); } /** @@ -1140,7 +1017,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the price() method in the Financial\Securities\Price class instead + * @see Financial\Securities\Price::price() + * Use the price() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date when the security @@ -1175,7 +1053,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the priceDiscounted() method in the Financial\Securities\Price class instead + * @see Financial\Securities\Price::priceDiscounted() + * Use the priceDiscounted() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date when the security @@ -1205,7 +1084,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the priceAtMaturity() method in the Financial\Securities\Price class instead + * @see Financial\Securities\Price::priceAtMaturity() + * Use the priceAtMaturity() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. * The security's settlement date is the date after the issue date when the security @@ -1234,6 +1114,11 @@ class Financial * * Returns the Present Value of a cash flow with constant payments and interest rate (annuities). * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic::presentValue() + * Use the presentValue() method in the Financial\CashFlow\Constant\Periodic class instead + * * @param float $rate Interest rate per period * @param int $nper Number of periods * @param float $pmt Periodic payment (annuity) @@ -1244,23 +1129,7 @@ class Financial */ public static function PV($rate = 0, $nper = 0, $pmt = 0, $fv = 0, $type = 0) { - $rate = Functions::flattenSingleValue($rate); - $nper = Functions::flattenSingleValue($nper); - $pmt = Functions::flattenSingleValue($pmt); - $fv = Functions::flattenSingleValue($fv); - $type = Functions::flattenSingleValue($type); - - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - - // Calculate - if ($rate !== null && $rate != 0) { - return (-$pmt * (1 + $rate * $type) * (((1 + $rate) ** $nper - 1) / $rate) - $fv) / (1 + $rate) ** $nper; - } - - return -$fv - $pmt * $nper; + return Financial\CashFlow\Constant\Periodic::presentValue($rate, $nper, $pmt, $fv, $type); } /** @@ -1274,6 +1143,11 @@ class Financial * Excel Function: * RATE(nper,pmt,pv[,fv[,type[,guess]]]) * + * @Deprecated 1.18.0 + * + * @see Financial\CashFlow\Constant\Periodic\Interest::rate() + * Use the rate() method in the Financial\CashFlow\Constant\Periodic class instead + * * @param mixed $nper The total number of payment periods in an annuity * @param mixed $pmt The payment made each period and cannot change over the life * of the annuity. @@ -1294,47 +1168,7 @@ class Financial */ public static function RATE($nper, $pmt, $pv, $fv = 0.0, $type = 0, $guess = 0.1) { - $nper = (int) Functions::flattenSingleValue($nper); - $pmt = Functions::flattenSingleValue($pmt); - $pv = Functions::flattenSingleValue($pv); - $fv = ($fv === null) ? 0.0 : Functions::flattenSingleValue($fv); - $type = ($type === null) ? 0 : (int) Functions::flattenSingleValue($type); - $guess = ($guess === null) ? 0.1 : Functions::flattenSingleValue($guess); - - $rate = $guess; - // rest of code adapted from python/numpy - $close = false; - $iter = 0; - while (!$close && $iter < self::FINANCIAL_MAX_ITERATIONS) { - $nextdiff = self::rateNextGuess($rate, $nper, $pmt, $pv, $fv, $type); - if (!is_numeric($nextdiff)) { - break; - } - $rate1 = $rate - $nextdiff; - $close = abs($rate1 - $rate) < self::FINANCIAL_PRECISION; - ++$iter; - $rate = $rate1; - } - - return $close ? $rate : Functions::NAN(); - } - - private static function rateNextGuess($rate, $nper, $pmt, $pv, $fv, $type) - { - if ($rate == 0) { - return Functions::NAN(); - } - $tt1 = ($rate + 1) ** $nper; - $tt2 = ($rate + 1) ** ($nper - 1); - $numerator = $fv + $tt1 * $pv + $pmt * ($tt1 - 1) * ($rate * $type + 1) / $rate; - $denominator = $nper * $tt2 * $pv - $pmt * ($tt1 - 1) * ($rate * $type + 1) / ($rate * $rate) - + $nper * $pmt * $tt2 * ($rate * $type + 1) / $rate - + $pmt * ($tt1 - 1) * $type / $rate; - if ($denominator == 0) { - return Functions::NAN(); - } - - return $numerator / $denominator; + return Financial\CashFlow\Constant\Periodic\Interest::rate($nper, $pmt, $pv, $fv, $type, $guess); } /** @@ -1343,17 +1177,18 @@ class Financial * Returns the price per $100 face value of a discounted security. * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. + * The security settlement date is the date after the issue 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. + * The maturity date is the date when the security expires. * @param mixed $investment The amount invested in the security * @param mixed $discount The security's discount rate * @param mixed $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ @@ -1410,7 +1245,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the SLN() method in the Financial\Depreciation class instead + * @see Financial\Depreciation::SLN() + * Use the SLN() method in the Financial\Depreciation class instead * * @param mixed $cost Initial cost of the asset * @param mixed $salvage Value at the end of the depreciation @@ -1430,7 +1266,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the SYD() method in the Financial\Depreciation class instead + * @see Financial\Depreciation::SYD() + * Use the SYD() method in the Financial\Depreciation class instead * * @param mixed $cost Initial cost of the asset * @param mixed $salvage Value at the end of the depreciation @@ -1451,10 +1288,12 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the bondEquivalentYield() method in the Financial\TreasuryBill class instead + * @see Financial\TreasuryBill::bondEquivalentYield() + * Use the bondEquivalentYield() method in the Financial\TreasuryBill class instead * * @param mixed $settlement The Treasury bill's settlement date. - * The Treasury bill's settlement date is the date after the issue date when the Treasury bill is traded to the buyer. + * The Treasury bill's settlement date is the date after the issue date 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 @@ -1473,7 +1312,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the price() method in the Financial\TreasuryBill class instead + * @see Financial\TreasuryBill::price() + * Use the price() method in the Financial\TreasuryBill class instead * * @param mixed $settlement The Treasury bill's settlement date. * The Treasury bill's settlement date is the date after the issue date @@ -1496,7 +1336,8 @@ class Financial * * @Deprecated 1.18.0 * - * @see Use the yield() method in the Financial\TreasuryBill class instead + * @see Financial\TreasuryBill::yield() + * Use the yield() method in the Financial\TreasuryBill class instead * * @param mixed $settlement The Treasury bill's settlement date. * The Treasury bill's settlement date is the date after the issue date @@ -1554,13 +1395,15 @@ class Financial * Use the presentValue() method in the Financial\CashFlow\Variable\NonPeriodic class instead * * @param float $rate the discount rate to apply to the cash flows - * @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates. - * The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. - * If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. - * The series of values must contain at least one positive value and one negative value. - * @param mixed[] $dates A schedule of payment dates that corresponds to the cash flow payments. - * The first payment date indicates the beginning of the schedule of payments. - * All other dates must be later than this date, but they may occur in any order. + * @param float[] $values A series of cash flows that corresponds to a schedule of payments in dates. + * The first payment is optional and corresponds to a cost or payment that occurs + * at the beginning of the investment. + * If the first value is a cost or payment, it must be a negative value. + * All succeeding payments are discounted based on a 365-day year. + * The series of values must contain at least one positive value and one negative value. + * @param mixed[] $dates A schedule of payment dates that corresponds to the cash flow payments. + * The first payment date indicates the beginning of the schedule of payments. + * All other dates must be later than this date, but they may occur in any order. * * @return float|mixed|string */ @@ -1619,11 +1462,11 @@ class Financial * @param int $rate The security's interest rate at date of issue * @param int $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 - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php new file mode 100644 index 00000000..39a51875 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php @@ -0,0 +1,190 @@ +getMessage(); + } + + // Validate parameters + if ($numberOfPeriods < 0 || ($type !== 0 && $type !== 1)) { + return Functions::NAN(); + } + + return self::calculateFutureValue($rate, $numberOfPeriods, $payment, $presentValue, $type); + } + + /** + * PV. + * + * Returns the Present Value of a cash flow with constant payments and interest rate (annuities). + * + * @param mixed $rate Interest rate per period + * @param mixed $numberOfPeriods Number of periods as an integer + * @param mixed $payment Periodic payment (annuity) + * @param mixed $futureValue Future Value + * @param mixed $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * + * @return float|string Result, or a string containing an error + */ + public static function presentValue($rate, $numberOfPeriods, $payment = 0, $futureValue = 0, $type = 0) + { + $rate = Functions::flattenSingleValue($rate); + $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); + $payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment); + $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); + $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + + try { + $rate = self::validateFloat($rate); + $numberOfPeriods = self::validateInt($numberOfPeriods); + $payment = self::validateFloat($payment); + $futureValue = self::validateFloat($futureValue); + $type = self::validateInt($type); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Validate parameters + if ($numberOfPeriods < 0 || ($type !== 0 && $type !== 1)) { + return Functions::NAN(); + } + + return self::calculatePresentValue($rate, $numberOfPeriods, $payment, $futureValue, $type); + } + + /** + * NPER. + * + * Returns the number of periods for a cash flow with constant periodic payments (annuities), and interest rate. + * + * @param mixed $rate Interest rate per period + * @param mixed $payment Periodic payment (annuity) + * @param mixed $presentValue Present Value + * @param mixed $futureValue Future Value + * @param mixed $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * + * @return float|string Result, or a string containing an error + */ + public static function periods($rate, $payment, $presentValue, $futureValue = 0, $type = 0) + { + $rate = Functions::flattenSingleValue($rate); + $payment = Functions::flattenSingleValue($payment); + $presentValue = Functions::flattenSingleValue($presentValue); + $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); + $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + + try { + $rate = self::validateFloat($rate); + $payment = self::validateFloat($payment); + $presentValue = self::validateFloat($presentValue); + $futureValue = self::validateFloat($futureValue); + $type = self::validateInt($type); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Validate parameters + if ($payment == 0.0 || ($type != 0 && $type != 1)) { + return Functions::NAN(); + } + + return self::calculatePeriods($rate, $payment, $presentValue, $futureValue, $type); + } + + private static function calculateFutureValue( + float $rate, + int $numberOfPeriods, + float $payment, + float $presentValue, + int $type + ): float { + if ($rate !== null && $rate != 0) { + return -$presentValue * + (1 + $rate) ** $numberOfPeriods - $payment * (1 + $rate * $type) * ((1 + $rate) ** $numberOfPeriods - 1) + / $rate; + } + + return -$presentValue - $payment * $numberOfPeriods; + } + + private static function calculatePresentValue( + float $rate, + int $numberOfPeriods, + float $payment, + float $futureValue, + int $type + ): float { + if ($rate != 0.0) { + return (-$payment * (1 + $rate * $type) + * (((1 + $rate) ** $numberOfPeriods - 1) / $rate) - $futureValue) / (1 + $rate) ** $numberOfPeriods; + } + + return -$futureValue - $payment * $numberOfPeriods; + } + + /** + * @return float|string + */ + private static function calculatePeriods( + float $rate, + float $payment, + float $presentValue, + float $futureValue, + int $type + ) { + if ($rate != 0.0) { + if ($presentValue == 0.0) { + return Functions::NAN(); + } + + return log(($payment * (1 + $rate * $type) / $rate - $futureValue) / + ($presentValue + $payment * (1 + $rate * $type) / $rate)) / log(1 + $rate); + } + + return (-$presentValue - $futureValue) / $payment; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php new file mode 100644 index 00000000..1e05a446 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php @@ -0,0 +1,136 @@ +getMessage(); + } + + // Validate parameters + if ($type !== 0 && $type !== 1) { + return Functions::NAN(); + } + if ($start < 1 || $start > $end) { + return Functions::NAN(); + } + + // Calculate + $interest = 0; + for ($per = $start; $per <= $end; ++$per) { + $ipmt = Financial::IPMT($rate, $per, $periods, $presentValue, 0, $type); + if (is_string($ipmt)) { + return $ipmt; + } + + $interest += $ipmt; + } + + return $interest; + } + + /** + * CUMPRINC. + * + * Returns the cumulative principal paid on a loan between the start and end periods. + * + * Excel Function: + * CUMPRINC(rate,nper,pv,start,end[,type]) + * + * @param mixed $rate The Interest rate + * @param mixed $periods The total number of payment periods as an integer + * @param mixed $presentValue Present Value + * @param mixed $start The first period in the calculation. + * Payment periods are numbered beginning with 1. + * @param mixed $end the last period in the calculation + * @param mixed $type A number 0 or 1 and indicates when payments are due: + * 0 or omitted At the end of the period. + * 1 At the beginning of the period. + * + * @return float|string + */ + public static function principal($rate, $periods, $presentValue, $start, $end, $type = 0) + { + $rate = Functions::flattenSingleValue($rate); + $periods = Functions::flattenSingleValue($periods); + $presentValue = Functions::flattenSingleValue($presentValue); + $start = Functions::flattenSingleValue($start); + $end = Functions::flattenSingleValue($end); + $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + + try { + $rate = self::validateFloat($rate); + $periods = self::validateInt($periods); + $presentValue = self::validateFloat($presentValue); + $start = self::validateInt($start); + $end = self::validateInt($end); + $type = self::validateInt($type); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Validate parameters + if ($type !== 0 && $type !== 1) { + return Functions::NAN(); + } + if ($start < 1 || $start > $end) { + return Functions::VALUE(); + } + + // Calculate + $principal = 0; + for ($per = $start; $per <= $end; ++$per) { + $ppmt = Payments::interestPayment($rate, $per, $periods, $presentValue, 0, $type); + if (is_string($ppmt)) { + return $ppmt; + } + + $principal += $ppmt; + } + + return $principal; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php new file mode 100644 index 00000000..1bb63a2a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php @@ -0,0 +1,209 @@ +getMessage(); + } + + // Validate parameters + if ($type != 0 && $type != 1) { + return Functions::NAN(); + } + if ($period <= 0 || $period > $numberOfPeriods) { + return Functions::NAN(); + } + + // Calculate + $interestAndPrincipal = new InterestAndPrincipal( + $interestRate, + $period, + $numberOfPeriods, + $presentValue, + $futureValue, + $type + ); + + return $interestAndPrincipal->interest(); + } + + /** + * ISPMT. + * + * Returns the interest payment for an investment based on an interest rate and a constant payment schedule. + * + * Excel Function: + * =ISPMT(interest_rate, period, number_payments, pv) + * + * interest_rate is the interest rate for the investment + * + * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments. + * + * number_payments is the number of payments for the annuity + * + * pv is the loan amount or present value of the payments + */ + public static function schedulePayment($interestRate, $period, $numberOfPeriods, $principleRemaining) + { + $interestRate = Functions::flattenSingleValue($interestRate); + $period = Functions::flattenSingleValue($period); + $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); + $principleRemaining = Functions::flattenSingleValue($principleRemaining); + + try { + $interestRate = self::validateFloat($interestRate); + $period = self::validateInt($period); + $numberOfPeriods = self::validateInt($numberOfPeriods); + $principleRemaining = self::validateFloat($principleRemaining); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($period <= 0 || $period > $numberOfPeriods) { + return Functions::NAN(); + } + // Return value + $returnValue = 0; + + // Calculate + $principlePayment = ($principleRemaining * 1.0) / ($numberOfPeriods * 1.0); + for ($i = 0; $i <= $period; ++$i) { + $returnValue = $interestRate * $principleRemaining * -1; + $principleRemaining -= $principlePayment; + // principle needs to be 0 after the last payment, don't let floating point screw it up + if ($i == $numberOfPeriods) { + $returnValue = 0.0; + } + } + + return $returnValue; + } + + /** + * RATE. + * + * Returns the interest rate per period of an annuity. + * RATE is calculated by iteration and can have zero or more solutions. + * If the successive results of RATE do not converge to within 0.0000001 after 20 iterations, + * RATE returns the #NUM! error value. + * + * Excel Function: + * RATE(nper,pmt,pv[,fv[,type[,guess]]]) + * + * @param mixed $numberOfPeriods The total number of payment periods in an annuity + * @param mixed $payment The payment made each period and cannot change over the life of the annuity. + * Typically, pmt includes principal and interest but no other fees or taxes. + * @param mixed $presentValue The present value - the total amount that a series of future payments is worth now + * @param mixed $futureValue The future value, or a cash balance you want to attain after the last payment is made. + * If fv is omitted, it is assumed to be 0 (the future value of a loan, + * for example, is 0). + * @param mixed $type A number 0 or 1 and indicates when payments are due: + * 0 or omitted At the end of the period. + * 1 At the beginning of the period. + * @param mixed $guess Your guess for what the rate will be. + * If you omit guess, it is assumed to be 10 percent. + * + * @return float|string + */ + public static function rate($numberOfPeriods, $payment, $presentValue, $futureValue = 0.0, $type = 0, $guess = 0.1) + { + $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); + $payment = Functions::flattenSingleValue($payment); + $presentValue = Functions::flattenSingleValue($presentValue); + $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); + $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $guess = ($guess === null) ? 0.1 : Functions::flattenSingleValue($guess); + + try { + $numberOfPeriods = self::validateInt($numberOfPeriods); + $payment = self::validateFloat($payment); + $presentValue = self::validateFloat($presentValue); + $futureValue = self::validateFloat($futureValue); + $type = self::validateInt($type); + $guess = self::validateFloat($guess); + } catch (Exception $e) { + return $e->getMessage(); + } + + $rate = $guess; + // rest of code adapted from python/numpy + $close = false; + $iter = 0; + while (!$close && $iter < self::FINANCIAL_MAX_ITERATIONS) { + $nextdiff = self::rateNextGuess($rate, $numberOfPeriods, $payment, $presentValue, $futureValue, $type); + if (!is_numeric($nextdiff)) { + break; + } + $rate1 = $rate - $nextdiff; + $close = abs($rate1 - $rate) < self::FINANCIAL_PRECISION; + ++$iter; + $rate = $rate1; + } + + return $close ? $rate : Functions::NAN(); + } + + private static function rateNextGuess($rate, $nper, $pmt, $pv, $fv, $type) + { + if ($rate == 0) { + return Functions::NAN(); + } + $tt1 = ($rate + 1) ** $nper; + $tt2 = ($rate + 1) ** ($nper - 1); + $numerator = $fv + $tt1 * $pv + $pmt * ($tt1 - 1) * ($rate * $type + 1) / $rate; + $denominator = $nper * $tt2 * $pv - $pmt * ($tt1 - 1) * ($rate * $type + 1) / ($rate * $rate) + + $nper * $pmt * $tt2 * ($rate * $type + 1) / $rate + + $pmt * ($tt1 - 1) * $type / $rate; + if ($denominator == 0) { + return Functions::NAN(); + } + + return $numerator / $denominator; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php new file mode 100644 index 00000000..5e76f346 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php @@ -0,0 +1,42 @@ +interest = $interest; + $this->principal = $principal; + } + + public function interest(): float + { + return $this->interest; + } + + public function principal(): float + { + return $this->principal; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php new file mode 100644 index 00000000..a0c61586 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php @@ -0,0 +1,119 @@ +getMessage(); + } + + // Validate parameters + if ($type != 0 && $type != 1) { + return Functions::NAN(); + } + + // Calculate + if ($interestRate != 0.0) { + return (-$futureValue - $presentValue * (1 + $interestRate) ** $numberOfPeriods) / + (1 + $interestRate * $type) / (((1 + $interestRate) ** $numberOfPeriods - 1) / $interestRate); + } + + return (-$presentValue - $futureValue) / $numberOfPeriods; + } + + /** + * PPMT. + * + * Returns the interest payment for a given period for an investment based on periodic, constant payments + * and a constant interest rate. + * + * @param mixed $interestRate Interest rate per period + * @param mixed $period Period for which we want to find the interest + * @param mixed $numberOfPeriods Number of periods + * @param mixed $presentValue Present Value + * @param mixed $futureValue Future Value + * @param mixed $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * + * @return float|string Result, or a string containing an error + */ + public static function interestPayment( + $interestRate, + $period, + $numberOfPeriods, + $presentValue, + $futureValue = 0, + $type = 0 + ) { + $interestRate = Functions::flattenSingleValue($interestRate); + $period = Functions::flattenSingleValue($period); + $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); + $presentValue = Functions::flattenSingleValue($presentValue); + $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); + $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + + try { + $interestRate = self::validateFloat($interestRate); + $period = self::validateInt($period); + $numberOfPeriods = self::validateInt($numberOfPeriods); + $presentValue = self::validateFloat($presentValue); + $futureValue = self::validateFloat($futureValue); + $type = self::validateInt($type); + } catch (Exception $e) { + return $e->getMessage(); + } + + // Validate parameters + if ($type != 0 && $type != 1) { + return Functions::NAN(); + } + if ($period <= 0 || $period > $numberOfPeriods) { + return Functions::NAN(); + } + + // Calculate + $interestAndPrincipal = new InterestAndPrincipal( + $interestRate, + $period, + $numberOfPeriods, + $presentValue, + $futureValue, + $type + ); + + return $interestAndPrincipal->principal(); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php index 58f8fdaf..40df776f 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php @@ -178,14 +178,12 @@ class NonPeriodic $valCount = count($values); try { + self::validateXnpv($rate, $values, $dates); $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); } catch (Exception $e) { return $e->getMessage(); } - $rslt = self::validateXnpv($rate, $values, $dates); - if ($rslt) { - return $rslt; - } + $xnpv = 0.0; for ($i = 0; $i < $valCount; ++$i) { if (!is_numeric($values[$i])) { @@ -212,23 +210,17 @@ class NonPeriodic return is_finite($xnpv) ? $xnpv : Functions::VALUE(); } - private static function validateXnpv($rate, $values, $dates) + private static function validateXnpv($rate, $values, $dates): void { if (!is_numeric($rate)) { - return Functions::VALUE(); + throw new Exception(Functions::VALUE()); } $valCount = count($values); if ($valCount != count($dates)) { - return Functions::NAN(); + throw new Exception(Functions::NAN()); } if ($valCount > 1 && ((min($values) > 0) || (max($values) < 0))) { - return Functions::NAN(); + throw new Exception(Functions::NAN()); } - $date0 = DateTimeExcel\Helpers::getDateValue($dates[0]); - if (is_string($date0)) { - return Functions::VALUE(); - } - - return ''; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php new file mode 100644 index 00000000..9f7cf755 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php @@ -0,0 +1,34 @@ + Date: Tue, 6 Apr 2021 22:57:35 +0200 Subject: [PATCH 176/187] Consolidate use of constants Remove link to deprecated method in favour of new method --- .../CashFlow/Constant/Periodic/Cumulative.php | 7 ++-- .../CashFlow/Constant/Periodic/Interest.php | 37 +++++++++---------- .../Calculation/Financial/Coupons.php | 6 ++- .../Financial/Securities/Constants.php | 3 ++ 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php index 1e05a446..4f6ed170 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php @@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\Constant\Perio use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Financial; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Cumulative @@ -30,7 +31,7 @@ class Cumulative * * @return float|string */ - public static function interest($rate, $periods, $presentValue, $start, $end, $type = 0) + public static function interest($rate, $periods, $presentValue, $start, $end, $type = Constants::END_OF_PERIOD) { $rate = Functions::flattenSingleValue($rate); $periods = Functions::flattenSingleValue($periods); @@ -51,7 +52,7 @@ class Cumulative } // Validate parameters - if ($type !== 0 && $type !== 1) { + if ($type !== Constants::END_OF_PERIOD && $type !== Constants::BEGINNING_OF_PERIOD) { return Functions::NAN(); } if ($start < 1 || $start > $end) { @@ -61,7 +62,7 @@ class Cumulative // Calculate $interest = 0; for ($per = $start; $per <= $end; ++$per) { - $ipmt = Financial::IPMT($rate, $per, $periods, $presentValue, 0, $type); + $ipmt = Interest::payment($rate, $per, $periods, $presentValue, 0, $type); if (is_string($ipmt)) { return $ipmt; } diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php index 1bb63a2a..3f579ce2 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php @@ -23,12 +23,12 @@ class Interest * Excel Function: * IPMT(rate,per,nper,pv[,fv][,type]) * - * @param float $interestRate Interest rate per period - * @param int $period Period for which we want to find the interest - * @param int $numberOfPeriods Number of periods - * @param float $presentValue Present Value - * @param float $futureValue Future Value - * @param int $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period + * @param mixed $interestRate Interest rate per period + * @param mixed $period Period for which we want to find the interest + * @param mixed $numberOfPeriods Number of periods + * @param mixed $presentValue Present Value + * @param mixed $futureValue Future Value + * @param mixed $type Payment type: 0 = at the end of each period, 1 = at the beginning of each period * * @return float|string */ @@ -81,13 +81,10 @@ class Interest * Excel Function: * =ISPMT(interest_rate, period, number_payments, pv) * - * interest_rate is the interest rate for the investment - * - * period is the period to calculate the interest rate. It must be betweeen 1 and number_payments. - * - * number_payments is the number of payments for the annuity - * - * pv is the loan amount or present value of the payments + * @param mixed $interestRate is the interest rate for the investment + * @param mixed $period is the period to calculate the interest rate. It must be betweeen 1 and number_payments. + * @param mixed $numberOfPeriods is the number of payments for the annuity + * @param mixed $principleRemaining is the loan amount or present value of the payments */ public static function schedulePayment($interestRate, $period, $numberOfPeriods, $principleRemaining) { @@ -189,17 +186,17 @@ class Interest return $close ? $rate : Functions::NAN(); } - private static function rateNextGuess($rate, $nper, $pmt, $pv, $fv, $type) + private static function rateNextGuess($rate, $numberOfPeriods, $payment, $presentValue, $futureValue, $type) { if ($rate == 0) { return Functions::NAN(); } - $tt1 = ($rate + 1) ** $nper; - $tt2 = ($rate + 1) ** ($nper - 1); - $numerator = $fv + $tt1 * $pv + $pmt * ($tt1 - 1) * ($rate * $type + 1) / $rate; - $denominator = $nper * $tt2 * $pv - $pmt * ($tt1 - 1) * ($rate * $type + 1) / ($rate * $rate) - + $nper * $pmt * $tt2 * ($rate * $type + 1) / $rate - + $pmt * ($tt1 - 1) * $type / $rate; + $tt1 = ($rate + 1) ** $numberOfPeriods; + $tt2 = ($rate + 1) ** ($numberOfPeriods - 1); + $numerator = $futureValue + $tt1 * $presentValue + $payment * ($tt1 - 1) * ($rate * $type + 1) / $rate; + $denominator = $numberOfPeriods * $tt2 * $presentValue - $payment * ($tt1 - 1) + * ($rate * $type + 1) / ($rate * $rate) + $numberOfPeriods + * $payment * $tt2 * ($rate * $type + 1) / $rate + $payment * ($tt1 - 1) * $type / $rate; if ($denominator == 0) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php index c24b31be..cdd54015 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Coupons.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Coupons.php @@ -291,7 +291,11 @@ class Coupons return $e->getMessage(); } - $yearsBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, 0); + $yearsBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac( + $settlement, + $maturity, + Helpers::DAYS_PER_YEAR_NASD + ); return (int) ceil($yearsBetweenSettlementAndMaturity * $frequency); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php index ba9d2389..f7bc2731 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php @@ -7,4 +7,7 @@ class Constants public const FREQUENCY_ANNUAL = 1; public const FREQUENCY_SEMI_ANNUAL = 2; public const FREQUENCY_QUARTERLY = 4; + + public const END_OF_PERIOD = 0; + public const BEGINNING_OF_PERIOD = 1; } From f9532231d2ba124713620a28ac39bd512d75c99e Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Sun, 4 Apr 2021 22:20:00 +0900 Subject: [PATCH 177/187] PHPStan Level 3 --- phpstan.neon.dist | 4 +- .../Calculation/Calculation.php | 4 +- .../Calculation/Database/DatabaseAbstract.php | 2 +- .../Calculation/Engineering.php | 4 +- .../Calculation/Engineering/ConvertBinary.php | 2 +- .../Calculation/Engineering/ConvertHex.php | 4 +- .../Calculation/Engineering/ConvertOctal.php | 4 +- .../Calculation/Engineering/ConvertUOM.php | 4 +- .../Calculation/FormulaParser.php | 4 +- src/PhpSpreadsheet/Calculation/Functions.php | 2 +- .../Calculation/LookupRef/Offset.php | 2 +- .../Calculation/MathTrig/Fact.php | 2 +- .../Calculation/Statistical.php | 4 +- .../Calculation/Statistical/Trends.php | 4 +- src/PhpSpreadsheet/Cell/Cell.php | 5 +- src/PhpSpreadsheet/Chart/Axis.php | 16 ++--- src/PhpSpreadsheet/Chart/DataSeries.php | 20 +++--- src/PhpSpreadsheet/Chart/DataSeriesValues.php | 4 +- src/PhpSpreadsheet/Chart/PlotArea.php | 2 +- src/PhpSpreadsheet/Collection/Cells.php | 6 +- src/PhpSpreadsheet/Document/Properties.php | 2 +- src/PhpSpreadsheet/HashTable.php | 4 +- src/PhpSpreadsheet/Reader/BaseReader.php | 2 +- src/PhpSpreadsheet/Reader/Xls.php | 6 +- src/PhpSpreadsheet/Reader/Xlsx.php | 5 +- src/PhpSpreadsheet/Reader/Xlsx/Theme.php | 12 ++-- src/PhpSpreadsheet/Settings.php | 2 +- src/PhpSpreadsheet/Shared/Date.php | 2 +- src/PhpSpreadsheet/Shared/Drawing.php | 6 +- src/PhpSpreadsheet/Shared/Font.php | 2 +- .../Shared/JAMA/LUDecomposition.php | 2 +- src/PhpSpreadsheet/Shared/JAMA/Matrix.php | 8 +-- .../Shared/OLE/ChainedBlockStream.php | 4 +- src/PhpSpreadsheet/Shared/OLERead.php | 2 +- src/PhpSpreadsheet/Shared/Trend/BestFit.php | 23 +++---- .../Shared/Trend/PolynomialBestFit.php | 5 +- src/PhpSpreadsheet/Shared/Xls.php | 10 +-- src/PhpSpreadsheet/Spreadsheet.php | 25 ++++---- src/PhpSpreadsheet/Style/Alignment.php | 12 ++-- src/PhpSpreadsheet/Style/Border.php | 2 +- src/PhpSpreadsheet/Style/Fill.php | 8 +-- src/PhpSpreadsheet/Style/Font.php | 34 +++++----- src/PhpSpreadsheet/Style/NumberFormat.php | 8 +-- src/PhpSpreadsheet/Worksheet/AutoFilter.php | 8 +-- .../Worksheet/AutoFilter/Column.php | 10 +-- .../Worksheet/AutoFilter/Column/Rule.php | 4 +- src/PhpSpreadsheet/Worksheet/BaseDrawing.php | 12 ++-- src/PhpSpreadsheet/Worksheet/CellIterator.php | 1 + src/PhpSpreadsheet/Worksheet/Column.php | 1 + .../Worksheet/ColumnCellIterator.php | 2 +- .../Worksheet/ColumnIterator.php | 1 + .../Worksheet/Drawing/Shadow.php | 6 +- src/PhpSpreadsheet/Worksheet/Iterator.php | 8 --- .../Worksheet/MemoryDrawing.php | 1 - src/PhpSpreadsheet/Worksheet/PageSetup.php | 2 +- src/PhpSpreadsheet/Worksheet/Row.php | 1 + src/PhpSpreadsheet/Worksheet/RowIterator.php | 8 --- src/PhpSpreadsheet/Worksheet/Worksheet.php | 34 +++++----- src/PhpSpreadsheet/Writer/Html.php | 4 +- src/PhpSpreadsheet/Writer/Pdf.php | 2 +- src/PhpSpreadsheet/Writer/Xls.php | 6 +- src/PhpSpreadsheet/Writer/Xls/BIFFwriter.php | 2 +- src/PhpSpreadsheet/Writer/Xls/Font.php | 2 +- src/PhpSpreadsheet/Writer/Xls/Worksheet.php | 63 +++++-------------- src/PhpSpreadsheet/Writer/Xls/Xf.php | 8 +-- src/PhpSpreadsheet/Writer/Xlsx.php | 7 +++ src/PhpSpreadsheet/Writer/Xlsx/DocProps.php | 4 +- src/PhpSpreadsheet/Writer/Xlsx/Theme.php | 6 +- .../Functions/Engineering/ImConjugateTest.php | 5 -- .../Functions/Engineering/ImCosTest.php | 5 -- .../Functions/Engineering/ImCoshTest.php | 5 -- .../Functions/Engineering/ImCotTest.php | 5 -- .../Functions/Engineering/ImCscTest.php | 5 -- .../Functions/Engineering/ImCschTest.php | 5 -- .../Functions/Engineering/ImDivTest.php | 5 -- .../Functions/Engineering/ImExpTest.php | 5 -- .../Functions/Engineering/ImLnTest.php | 5 -- .../Functions/Engineering/ImLog10Test.php | 5 -- .../Functions/Engineering/ImLog2Test.php | 5 -- .../Functions/Engineering/ImPowerTest.php | 5 -- .../Functions/Engineering/ImProductTest.php | 5 -- .../Functions/Engineering/ImSecTest.php | 5 -- .../Functions/Engineering/ImSechTest.php | 5 -- .../Functions/Engineering/ImSinTest.php | 5 -- .../Functions/Engineering/ImSinhTest.php | 5 -- .../Functions/Engineering/ImSqrtTest.php | 5 -- .../Functions/Engineering/ImSubTest.php | 5 -- .../Functions/Engineering/ImSumTest.php | 5 -- .../Functions/Engineering/ImTanTest.php | 5 -- tests/PhpSpreadsheetTests/SettingsTest.php | 2 +- 90 files changed, 225 insertions(+), 370 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 53bbb0e6..6917c78c 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,8 +1,10 @@ parameters: - level: 2 + level: 3 paths: - src/ - tests/ + parallel: + processTimeout: 300.0 ignoreErrors: - '~^Class GdImage not found\.$~' - '~^Return typehint of method .* has invalid type GdImage\.$~' diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 9477131f..a11b8a12 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -5234,10 +5234,8 @@ class Calculation /** * Get a list of all implemented functions as an array of function objects. - * - * @return array of Category */ - public function getFunctions() + public function getFunctions(): array { return self::$phpSpreadsheetFunctions; } diff --git a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php index cf48bd88..2c9bb2de 100644 --- a/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php +++ b/src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php @@ -57,7 +57,7 @@ abstract class DatabaseAbstract * the column label in which you specify a condition for the * column. * - * @return array of mixed + * @return mixed[] */ protected static function filter(array $database, array $criteria): array { diff --git a/src/PhpSpreadsheet/Calculation/Engineering.php b/src/PhpSpreadsheet/Calculation/Engineering.php index 7584556a..a70ddac5 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering.php +++ b/src/PhpSpreadsheet/Calculation/Engineering.php @@ -1395,7 +1395,7 @@ class Engineering * * @see Use the getConversionMultipliers() method in the ConvertUOM class instead * - * @return array of mixed + * @return mixed[] */ public static function getConversionMultipliers() { @@ -1412,7 +1412,7 @@ class Engineering * * @see Use the getBinaryConversionMultipliers() method in the ConvertUOM class instead * - * @return array of mixed + * @return mixed[] */ public static function getBinaryConversionMultipliers() { diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php index ff4873ac..a662b78d 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertBinary.php @@ -38,7 +38,7 @@ class ConvertBinary extends ConvertBase return '-' . (512 - bindec($value)); } - return bindec($value); + return (string) bindec($value); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php index cbf155ed..de1b0704 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php @@ -85,10 +85,10 @@ class ConvertHex extends ConvertBase $binX[$i] = ($binX[$i] == '1' ? '0' : '1'); } - return (bindec($binX) + 1) * -1; + return (string) ((bindec($binX) + 1) * -1); } - return bindec($binX); + return (string) bindec($binX); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php index 872f0b70..1181e2ee 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertOctal.php @@ -85,10 +85,10 @@ class ConvertOctal extends ConvertBase $binX[$i] = ($binX[$i] == '1' ? '0' : '1'); } - return (bindec($binX) + 1) * -1; + return (string) ((bindec($binX) + 1) * -1); } - return bindec($binX); + return (string) bindec($binX); } /** diff --git a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php index 0aafe05e..d169ae54 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php @@ -490,7 +490,7 @@ class ConvertUOM * getConversionMultipliers * Returns an array of the Multiplier prefixes that can be used with Units of Measure in CONVERTUOM(). * - * @return array of mixed + * @return mixed[] */ public static function getConversionMultipliers() { @@ -501,7 +501,7 @@ class ConvertUOM * getBinaryConversionMultipliers * Returns an array of the additional Multiplier prefixes that can be used with Information Units of Measure in CONVERTUOM(). * - * @return array of mixed + * @return mixed[] */ public static function getBinaryConversionMultipliers() { diff --git a/src/PhpSpreadsheet/Calculation/FormulaParser.php b/src/PhpSpreadsheet/Calculation/FormulaParser.php index c11af834..cd1402fd 100644 --- a/src/PhpSpreadsheet/Calculation/FormulaParser.php +++ b/src/PhpSpreadsheet/Calculation/FormulaParser.php @@ -90,10 +90,8 @@ class FormulaParser * Get Token. * * @param int $pId Token id - * - * @return string */ - public function getToken($pId = 0) + public function getToken(int $pId = 0): FormulaToken { if (isset($this->tokens[$pId])) { return $this->tokens[$pId]; diff --git a/src/PhpSpreadsheet/Calculation/Functions.php b/src/PhpSpreadsheet/Calculation/Functions.php index 34ebefed..aea2323e 100644 --- a/src/PhpSpreadsheet/Calculation/Functions.php +++ b/src/PhpSpreadsheet/Calculation/Functions.php @@ -303,7 +303,7 @@ class Functions * * @param mixed $value Value to check * - * @return bool + * @return int|string */ public static function errorType($value = '') { diff --git a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php index 25ec498b..c027d83c 100644 --- a/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php +++ b/src/PhpSpreadsheet/Calculation/LookupRef/Offset.php @@ -38,7 +38,7 @@ class Offset * @param mixed $width The width, in number of columns, that you want the returned reference to be. * Width must be a positive number. * - * @return array|string An array containing a cell or range of cells, or a string on error + * @return array|int|string An array containing a cell or range of cells, or a string on error */ public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $height = null, $width = null, ?Cell $pCell = null) { diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php b/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php index 026cb9a2..298ccbac 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Fact.php @@ -19,7 +19,7 @@ class Fact * * @param float $factVal Factorial Value * - * @return int|string Factorial, or a string containing an error + * @return float|int|string Factorial, or a string containing an error */ public static function funcFact($factVal) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index 003f06be..a0f4cd7c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -729,7 +729,7 @@ class Statistical * @param mixed[] $newValues Values of X for which we want to find Y * @param bool $const a logical value specifying whether to force the intersect to equal 0 * - * @return array of float + * @return float[] */ public static function GROWTH($yValues, $xValues = [], $newValues = [], $const = true) { @@ -1795,7 +1795,7 @@ class Statistical * @param mixed[] $newValues Values of X for which we want to find Y * @param bool $const a logical value specifying whether to force the intersect to equal 0 * - * @return array of float + * @return float[] */ public static function TREND($yValues, $xValues = [], $newValues = [], $const = true) { diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php index e745d1b7..f1fd91ae 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Trends.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Trends.php @@ -142,7 +142,7 @@ class Trends * @param mixed[] $newValues Values of X for which we want to find Y * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not * - * @return array of float + * @return float[] */ public static function GROWTH($yValues, $xValues = [], $newValues = [], $const = true) { @@ -399,7 +399,7 @@ class Trends * @param mixed[] $newValues Values of X for which we want to find Y * @param mixed $const A logical (boolean) value specifying whether to force the intersect to equal 0 or not * - * @return array of float + * @return float[] */ public static function TREND($yValues, $xValues = [], $newValues = [], $const = true) { diff --git a/src/PhpSpreadsheet/Cell/Cell.php b/src/PhpSpreadsheet/Cell/Cell.php index f971a3c8..89aa32cd 100644 --- a/src/PhpSpreadsheet/Cell/Cell.php +++ b/src/PhpSpreadsheet/Cell/Cell.php @@ -78,6 +78,7 @@ class Cell public function detach(): void { + // @phpstan-ignore-next-line $this->parent = null; } @@ -201,7 +202,7 @@ class Cell break; case DataType::TYPE_STRING2: $pDataType = DataType::TYPE_STRING; - // no break + // no break case DataType::TYPE_STRING: // Synonym for string case DataType::TYPE_INLINE: @@ -563,7 +564,7 @@ class Cell // Verify if cell is in range return ($rangeStart[0] <= $myColumn) && ($rangeEnd[0] >= $myColumn) && - ($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow); + ($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow); } /** diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php index 6a2e2df5..27e61060 100644 --- a/src/PhpSpreadsheet/Chart/Axis.php +++ b/src/PhpSpreadsheet/Chart/Axis.php @@ -13,7 +13,7 @@ class Axis extends Properties /** * Axis Number. * - * @var array of mixed + * @var mixed[] */ private $axisNumber = [ 'format' => self::FORMAT_CODE_GENERAL, @@ -23,7 +23,7 @@ class Axis extends Properties /** * Axis Options. * - * @var array of mixed + * @var mixed[] */ private $axisOptions = [ 'minimum' => null, @@ -41,7 +41,7 @@ class Axis extends Properties /** * Fill Properties. * - * @var array of mixed + * @var mixed[] */ private $fillProperties = [ 'type' => self::EXCEL_COLOR_TYPE_ARGB, @@ -52,7 +52,7 @@ class Axis extends Properties /** * Line Properties. * - * @var array of mixed + * @var mixed[] */ private $lineProperties = [ 'type' => self::EXCEL_COLOR_TYPE_ARGB, @@ -63,7 +63,7 @@ class Axis extends Properties /** * Line Style Properties. * - * @var array of mixed + * @var mixed[] */ private $lineStyleProperties = [ 'width' => '9525', @@ -86,7 +86,7 @@ class Axis extends Properties /** * Shadow Properties. * - * @var array of mixed + * @var mixed[] */ private $shadowProperties = [ 'presets' => self::SHADOW_PRESETS_NOSHADOW, @@ -111,7 +111,7 @@ class Axis extends Properties /** * Glow Properties. * - * @var array of mixed + * @var mixed[] */ private $glowProperties = [ 'size' => null, @@ -125,7 +125,7 @@ class Axis extends Properties /** * Soft Edge Properties. * - * @var array of mixed + * @var mixed[] */ private $softEdges = [ 'size' => null, diff --git a/src/PhpSpreadsheet/Chart/DataSeries.php b/src/PhpSpreadsheet/Chart/DataSeries.php index 3a44b335..067d30e5 100644 --- a/src/PhpSpreadsheet/Chart/DataSeries.php +++ b/src/PhpSpreadsheet/Chart/DataSeries.php @@ -75,21 +75,21 @@ class DataSeries /** * Order of plots in Series. * - * @var array of integer + * @var int[] */ private $plotOrder = []; /** * Plot Label. * - * @var array of DataSeriesValues + * @var DataSeriesValues[] */ private $plotLabel = []; /** * Plot Category. * - * @var array of DataSeriesValues + * @var DataSeriesValues[] */ private $plotCategory = []; @@ -103,7 +103,7 @@ class DataSeries /** * Plot Values. * - * @var array of DataSeriesValues + * @var DataSeriesValues[] */ private $plotValues = []; @@ -231,7 +231,7 @@ class DataSeries /** * Get Plot Labels. * - * @return array of DataSeriesValues + * @return DataSeriesValues[] */ public function getPlotLabels() { @@ -243,7 +243,7 @@ class DataSeries * * @param mixed $index * - * @return DataSeriesValues + * @return DataSeriesValues|false */ public function getPlotLabelByIndex($index) { @@ -260,7 +260,7 @@ class DataSeries /** * Get Plot Categories. * - * @return array of DataSeriesValues + * @return DataSeriesValues[] */ public function getPlotCategories() { @@ -272,7 +272,7 @@ class DataSeries * * @param mixed $index * - * @return DataSeriesValues + * @return DataSeriesValues|false */ public function getPlotCategoryByIndex($index) { @@ -313,7 +313,7 @@ class DataSeries /** * Get Plot Values. * - * @return array of DataSeriesValues + * @return DataSeriesValues[] */ public function getPlotValues() { @@ -325,7 +325,7 @@ class DataSeries * * @param mixed $index * - * @return DataSeriesValues + * @return DataSeriesValues|false */ public function getPlotValuesByIndex($index) { diff --git a/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/src/PhpSpreadsheet/Chart/DataSeriesValues.php index c1bd973a..88063336 100644 --- a/src/PhpSpreadsheet/Chart/DataSeriesValues.php +++ b/src/PhpSpreadsheet/Chart/DataSeriesValues.php @@ -55,7 +55,7 @@ class DataSeriesValues /** * Data Values. * - * @var array of mixed + * @var mixed[] */ private $dataValues = []; @@ -313,7 +313,7 @@ class DataSeriesValues /** * Get Series Data Values. * - * @return array of mixed + * @return mixed[] */ public function getDataValues() { diff --git a/src/PhpSpreadsheet/Chart/PlotArea.php b/src/PhpSpreadsheet/Chart/PlotArea.php index fbd01184..ecb7b6c9 100644 --- a/src/PhpSpreadsheet/Chart/PlotArea.php +++ b/src/PhpSpreadsheet/Chart/PlotArea.php @@ -67,7 +67,7 @@ class PlotArea /** * Get Plot Series. * - * @return array of DataSeries + * @return DataSeries[] */ public function getPlotGroup() { diff --git a/src/PhpSpreadsheet/Collection/Cells.php b/src/PhpSpreadsheet/Collection/Cells.php index 48f34f41..7859965b 100644 --- a/src/PhpSpreadsheet/Collection/Cells.php +++ b/src/PhpSpreadsheet/Collection/Cells.php @@ -19,21 +19,21 @@ class Cells /** * Parent worksheet. * - * @var Worksheet + * @var null|Worksheet */ private $parent; /** * The currently active Cell. * - * @var Cell + * @var null|Cell */ private $currentCell; /** * Coordinate of the currently active Cell. * - * @var string + * @var null|string */ private $currentCoordinate; diff --git a/src/PhpSpreadsheet/Document/Properties.php b/src/PhpSpreadsheet/Document/Properties.php index 911d53ce..c099bccc 100644 --- a/src/PhpSpreadsheet/Document/Properties.php +++ b/src/PhpSpreadsheet/Document/Properties.php @@ -100,7 +100,7 @@ class Properties /** * Custom Properties. * - * @var string[] + * @var array{value: mixed, type: string}[] */ private $customProperties = []; diff --git a/src/PhpSpreadsheet/HashTable.php b/src/PhpSpreadsheet/HashTable.php index 0823236c..5d4444e7 100644 --- a/src/PhpSpreadsheet/HashTable.php +++ b/src/PhpSpreadsheet/HashTable.php @@ -126,7 +126,7 @@ class HashTable * * @param int $pIndex * - * @return T + * @return null|T */ public function getByIndex($pIndex) { @@ -142,7 +142,7 @@ class HashTable * * @param string $pHashCode * - * @return T + * @return null|T */ public function getByHashCode($pHashCode) { diff --git a/src/PhpSpreadsheet/Reader/BaseReader.php b/src/PhpSpreadsheet/Reader/BaseReader.php index eb0e3ba2..80348132 100644 --- a/src/PhpSpreadsheet/Reader/BaseReader.php +++ b/src/PhpSpreadsheet/Reader/BaseReader.php @@ -38,7 +38,7 @@ abstract class BaseReader implements IReader * Restrict which sheets should be loaded? * This property holds an array of worksheet names to be loaded. If null, then all worksheets will be loaded. * - * @var array of string + * @var null|string[] */ protected $loadSheetsOnly; diff --git a/src/PhpSpreadsheet/Reader/Xls.php b/src/PhpSpreadsheet/Reader/Xls.php index 35b55bc0..c389105b 100644 --- a/src/PhpSpreadsheet/Reader/Xls.php +++ b/src/PhpSpreadsheet/Reader/Xls.php @@ -374,7 +374,7 @@ class Xls extends BaseReader * * @var int */ - private $encryptionStartPos = false; + private $encryptionStartPos = 0; /** * The current RC4 decryption object. @@ -659,7 +659,7 @@ class Xls extends BaseReader $this->definedname = []; $this->sst = []; $this->drawingGroupData = ''; - $this->xfIndex = ''; + $this->xfIndex = 0; $this->mapCellXfIndex = []; $this->mapCellStyleXfIndex = []; @@ -1296,7 +1296,7 @@ class Xls extends BaseReader // TODO Provide support for named values } } - $this->data = null; + $this->data = ''; return $this->spreadsheet; } diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index 85b6c174..cd0fd149 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -879,10 +879,11 @@ class Xlsx extends BaseReader // Loop through contents foreach ($commentsFile->commentList->comment as $comment) { + $commentModel = $docSheet->getComment((string) $comment['ref']); if (!empty($comment['authorId'])) { - $docSheet->getComment((string) $comment['ref'])->setAuthor($authors[(string) $comment['authorId']]); + $commentModel->setAuthor($authors[$comment['authorId']]); } - $docSheet->getComment((string) $comment['ref'])->setText($this->parseRichText($comment->text)); + $commentModel->setText($this->parseRichText($comment->text)); } } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Theme.php b/src/PhpSpreadsheet/Reader/Xlsx/Theme.php index c105f3c1..1f2b863c 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Theme.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Theme.php @@ -21,16 +21,16 @@ class Theme /** * Colour Map. * - * @var array of string + * @var string[] */ private $colourMap; /** * Create a new Theme. * - * @param mixed $themeName - * @param mixed $colourSchemeName - * @param mixed $colourMap + * @param string $themeName + * @param string $colourSchemeName + * @param string[] $colourMap */ public function __construct($themeName, $colourSchemeName, $colourMap) { @@ -63,9 +63,9 @@ class Theme /** * Get colour Map Value by Position. * - * @param mixed $index + * @param int $index * - * @return string + * @return null|string */ public function getColourByIndex($index) { diff --git a/src/PhpSpreadsheet/Settings.php b/src/PhpSpreadsheet/Settings.php index cfa50573..8fdccbad 100644 --- a/src/PhpSpreadsheet/Settings.php +++ b/src/PhpSpreadsheet/Settings.php @@ -118,7 +118,7 @@ class Settings if (self::$libXmlLoaderOptions === null && defined('LIBXML_DTDLOAD')) { self::setLibXmlLoaderOptions(LIBXML_DTDLOAD | LIBXML_DTDATTR); } elseif (self::$libXmlLoaderOptions === null) { - self::$libXmlLoaderOptions = true; + self::$libXmlLoaderOptions = 0; } return self::$libXmlLoaderOptions; diff --git a/src/PhpSpreadsheet/Shared/Date.php b/src/PhpSpreadsheet/Shared/Date.php index 49b3425c..898dd523 100644 --- a/src/PhpSpreadsheet/Shared/Date.php +++ b/src/PhpSpreadsheet/Shared/Date.php @@ -255,7 +255,7 @@ class Date * * @param int $dateValue Unix Timestamp * - * @return float MS Excel serialized date/time value + * @return false|float MS Excel serialized date/time value */ public static function timestampToExcel($dateValue) { diff --git a/src/PhpSpreadsheet/Shared/Drawing.php b/src/PhpSpreadsheet/Shared/Drawing.php index 67c015c4..ebb87ed1 100644 --- a/src/PhpSpreadsheet/Shared/Drawing.php +++ b/src/PhpSpreadsheet/Shared/Drawing.php @@ -15,7 +15,7 @@ class Drawing */ public static function pixelsToEMU($pValue) { - return round($pValue * 9525); + return $pValue * 9525; } /** @@ -28,7 +28,7 @@ class Drawing public static function EMUToPixels($pValue) { if ($pValue != 0) { - return round($pValue / 9525); + return (int) round($pValue / 9525); } return 0; @@ -141,7 +141,7 @@ class Drawing public static function angleToDegrees($pValue) { if ($pValue != 0) { - return round($pValue / 60000); + return (int) round($pValue / 60000); } return 0; diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index 94e35dfe..00629e69 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -268,7 +268,7 @@ class Font $columnWidth = Drawing::pixelsToCellDimension($columnWidth, $defaultFont); // Return - return round($columnWidth, 6); + return (int) round($columnWidth, 6); } /** diff --git a/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php b/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php index e16d6a21..ecfe42ba 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php +++ b/src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php @@ -221,7 +221,7 @@ class LUDecomposition /** * Count determinants. * - * @return array d matrix deterninat + * @return float */ public function det() { diff --git a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php index 9cbc9530..adf399ac 100644 --- a/src/PhpSpreadsheet/Shared/JAMA/Matrix.php +++ b/src/PhpSpreadsheet/Shared/JAMA/Matrix.php @@ -147,7 +147,7 @@ class Matrix * @param int $i Row position * @param int $j Column position * - * @return mixed Element (int/float/double) + * @return float|int */ public function get($i = null, $j = null) { @@ -323,11 +323,9 @@ class Matrix * * @param int $i Row position * @param int $j Column position - * @param mixed $c Int/float/double value - * - * @return mixed Element (int/float/double) + * @param float|int $c value */ - public function set($i = null, $j = null, $c = null) + public function set($i = null, $j = null, $c = null): void { // Optimized set version just has this $this->A[$i][$j] = $c; diff --git a/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php b/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php index 1863ae34..43e4804d 100644 --- a/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php +++ b/src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php @@ -9,7 +9,7 @@ class ChainedBlockStream /** * The OLE container of the file that is being read. * - * @var OLE + * @var null|OLE */ public $ole; @@ -112,7 +112,7 @@ class ChainedBlockStream * * @param int $count maximum number of bytes to read * - * @return string + * @return false|string */ public function stream_read($count) // @codingStandardsIgnoreLine { diff --git a/src/PhpSpreadsheet/Shared/OLERead.php b/src/PhpSpreadsheet/Shared/OLERead.php index 78417741..c4dc572a 100644 --- a/src/PhpSpreadsheet/Shared/OLERead.php +++ b/src/PhpSpreadsheet/Shared/OLERead.php @@ -188,7 +188,7 @@ class OLERead * * @param int $stream * - * @return string + * @return null|string */ public function getStream($stream) { diff --git a/src/PhpSpreadsheet/Shared/Trend/BestFit.php b/src/PhpSpreadsheet/Shared/Trend/BestFit.php index 6d6f6283..7df48953 100644 --- a/src/PhpSpreadsheet/Shared/Trend/BestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/BestFit.php @@ -2,7 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared\Trend; -class BestFit +abstract class BestFit { /** * Indicator flag for a calculation error. @@ -96,24 +96,18 @@ class BestFit * * @param float $xValue X-Value * - * @return bool Y-Value + * @return float Y-Value */ - public function getValueOfYForX($xValue) - { - return false; - } + abstract public function getValueOfYForX($xValue); /** * Return the X-Value for a specified value of Y. * * @param float $yValue Y-Value * - * @return bool X-Value + * @return float X-Value */ - public function getValueOfXForY($yValue) - { - return false; - } + abstract public function getValueOfXForY($yValue); /** * Return the original set of X-Values. @@ -130,12 +124,9 @@ class BestFit * * @param int $dp Number of places of decimal precision to display * - * @return bool + * @return string */ - public function getEquation($dp = 0) - { - return false; - } + abstract public function getEquation($dp = 0); /** * Return the Slope of the line. diff --git a/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php b/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php index 1d34e81c..2c8eea5b 100644 --- a/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php +++ b/src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php @@ -42,6 +42,7 @@ class PolynomialBestFit extends BestFit { $retVal = $this->getIntersect(); $slope = $this->getSlope(); + // @phpstan-ignore-next-line foreach ($slope as $key => $value) { if ($value != 0.0) { $retVal += $value * $xValue ** ($key + 1); @@ -76,6 +77,7 @@ class PolynomialBestFit extends BestFit $intersect = $this->getIntersect($dp); $equation = 'Y = ' . $intersect; + // @phpstan-ignore-next-line foreach ($slope as $key => $value) { if ($value != 0.0) { $equation .= ' + ' . $value . ' * X'; @@ -93,7 +95,7 @@ class PolynomialBestFit extends BestFit * * @param int $dp Number of places of decimal precision to display * - * @return string + * @return float */ public function getSlope($dp = 0) { @@ -103,6 +105,7 @@ class PolynomialBestFit extends BestFit $coefficients[] = round($coefficient, $dp); } + // @phpstan-ignore-next-line return $coefficients; } diff --git a/src/PhpSpreadsheet/Shared/Xls.php b/src/PhpSpreadsheet/Shared/Xls.php index b3cdbd7d..26035ec6 100644 --- a/src/PhpSpreadsheet/Shared/Xls.php +++ b/src/PhpSpreadsheet/Shared/Xls.php @@ -205,7 +205,7 @@ class Xls * @param int $width Width in pixels * @param int $height Height in pixels * - * @return array + * @return null|array */ public static function oneAnchor2twoAnchor($sheet, $coordinates, $offsetX, $offsetY, $width, $height) { @@ -245,16 +245,16 @@ class Xls // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell // with zero height or width. if (self::sizeCol($sheet, Coordinate::stringFromColumnIndex($col_start)) == 0) { - return; + return null; } if (self::sizeCol($sheet, Coordinate::stringFromColumnIndex($col_end)) == 0) { - return; + return null; } if (self::sizeRow($sheet, $row_start + 1) == 0) { - return; + return null; } if (self::sizeRow($sheet, $row_end + 1) == 0) { - return; + return null; } // Convert the pixel values to the percentage value expected by Excel diff --git a/src/PhpSpreadsheet/Spreadsheet.php b/src/PhpSpreadsheet/Spreadsheet.php index 59304804..fb945399 100644 --- a/src/PhpSpreadsheet/Spreadsheet.php +++ b/src/PhpSpreadsheet/Spreadsheet.php @@ -69,7 +69,7 @@ class Spreadsheet /** * Named ranges. * - * @var NamedRange[] + * @var DefinedName[] */ private $definedNames = []; @@ -104,21 +104,21 @@ class Spreadsheet /** * macrosCode : all macros code as binary data (the vbaProject.bin file, this include form, code, etc.), null if no macro. * - * @var string + * @var null|string */ private $macrosCode; /** * macrosCertificate : if macros are signed, contains binary data vbaProjectSignature.bin file, null if not signed. * - * @var string + * @var null|string */ private $macrosCertificate; /** * ribbonXMLData : null if workbook is'nt Excel 2007 or not contain a customized UI. * - * @var null|string + * @var null|array{target: string, data: string} */ private $ribbonXMLData; @@ -298,11 +298,9 @@ class Spreadsheet /** * retrieve ribbon XML Data. * - * return string|null|array - * * @param string $what * - * @return string + * @return null|array|string */ public function getRibbonXMLData($what = 'all') //we need some constants here... { @@ -455,7 +453,7 @@ class Spreadsheet * * @param string $pName Sheet name * - * @return Worksheet + * @return null|Worksheet */ public function getSheetByCodeName($pName) { @@ -515,12 +513,10 @@ class Spreadsheet */ public function disconnectWorksheets(): void { - $worksheet = null; - foreach ($this->workSheetCollection as $k => &$worksheet) { + foreach ($this->workSheetCollection as $worksheet) { $worksheet->disconnectCells(); - $this->workSheetCollection[$k] = null; + unset($worksheet); } - unset($worksheet); $this->workSheetCollection = []; } @@ -876,7 +872,7 @@ class Spreadsheet /** * Get an array of all Named Ranges. * - * @return NamedRange[] + * @return DefinedName[] */ public function getNamedRanges(): array { @@ -891,7 +887,7 @@ class Spreadsheet /** * Get an array of all Named Formulae. * - * @return NamedFormula[] + * @return DefinedName[] */ public function getNamedFormulae(): array { @@ -1124,6 +1120,7 @@ class Spreadsheet */ public function __clone() { + // @phpstan-ignore-next-line foreach ($this as $key => $val) { if (is_object($val) || (is_array($val))) { $this->{$key} = unserialize(serialize($val)); diff --git a/src/PhpSpreadsheet/Style/Alignment.php b/src/PhpSpreadsheet/Style/Alignment.php index 226a5427..e072c524 100644 --- a/src/PhpSpreadsheet/Style/Alignment.php +++ b/src/PhpSpreadsheet/Style/Alignment.php @@ -35,21 +35,21 @@ class Alignment extends Supervisor /** * Horizontal alignment. * - * @var string + * @var null|string */ protected $horizontal = self::HORIZONTAL_GENERAL; /** * Vertical alignment. * - * @var string + * @var null|string */ protected $vertical = self::VERTICAL_BOTTOM; /** * Text rotation. * - * @var int + * @var null|int */ protected $textRotation = 0; @@ -179,7 +179,7 @@ class Alignment extends Supervisor /** * Get Horizontal. * - * @return string + * @return null|string */ public function getHorizontal() { @@ -216,7 +216,7 @@ class Alignment extends Supervisor /** * Get Vertical. * - * @return string + * @return null|string */ public function getVertical() { @@ -253,7 +253,7 @@ class Alignment extends Supervisor /** * Get TextRotation. * - * @return int + * @return null|int */ public function getTextRotation() { diff --git a/src/PhpSpreadsheet/Style/Border.php b/src/PhpSpreadsheet/Style/Border.php index dee1ad4c..a8af9d94 100644 --- a/src/PhpSpreadsheet/Style/Border.php +++ b/src/PhpSpreadsheet/Style/Border.php @@ -37,7 +37,7 @@ class Border extends Supervisor protected $color; /** - * @var int + * @var null|int */ public $colorIndex; diff --git a/src/PhpSpreadsheet/Style/Fill.php b/src/PhpSpreadsheet/Style/Fill.php index 3891bc47..e793f1e7 100644 --- a/src/PhpSpreadsheet/Style/Fill.php +++ b/src/PhpSpreadsheet/Style/Fill.php @@ -28,19 +28,19 @@ class Fill extends Supervisor const FILL_PATTERN_MEDIUMGRAY = 'mediumGray'; /** - * @var int + * @var null|int */ public $startcolorIndex; /** - * @var int + * @var null|int */ public $endcolorIndex; /** * Fill type. * - * @var string + * @var null|string */ protected $fillType = self::FILL_NONE; @@ -168,7 +168,7 @@ class Fill extends Supervisor /** * Get Fill Type. * - * @return string + * @return null|string */ public function getFillType() { diff --git a/src/PhpSpreadsheet/Style/Font.php b/src/PhpSpreadsheet/Style/Font.php index ad405708..473fe1dc 100644 --- a/src/PhpSpreadsheet/Style/Font.php +++ b/src/PhpSpreadsheet/Style/Font.php @@ -14,56 +14,56 @@ class Font extends Supervisor /** * Font Name. * - * @var string + * @var null|string */ protected $name = 'Calibri'; /** * Font Size. * - * @var float + * @var null|float */ protected $size = 11; /** * Bold. * - * @var bool + * @var null|bool */ protected $bold = false; /** * Italic. * - * @var bool + * @var null|bool */ protected $italic = false; /** * Superscript. * - * @var bool + * @var null|bool */ protected $superscript = false; /** * Subscript. * - * @var bool + * @var null|bool */ protected $subscript = false; /** * Underline. * - * @var string + * @var null|string */ protected $underline = self::UNDERLINE_NONE; /** * Strikethrough. * - * @var bool + * @var null|bool */ protected $strikethrough = false; @@ -75,7 +75,7 @@ class Font extends Supervisor protected $color; /** - * @var int + * @var null|int */ public $colorIndex; @@ -199,7 +199,7 @@ class Font extends Supervisor /** * Get Name. * - * @return string + * @return null|string */ public function getName() { @@ -235,7 +235,7 @@ class Font extends Supervisor /** * Get Size. * - * @return float + * @return null|float */ public function getSize() { @@ -271,7 +271,7 @@ class Font extends Supervisor /** * Get Bold. * - * @return bool + * @return null|bool */ public function getBold() { @@ -307,7 +307,7 @@ class Font extends Supervisor /** * Get Italic. * - * @return bool + * @return null|bool */ public function getItalic() { @@ -343,7 +343,7 @@ class Font extends Supervisor /** * Get Superscript. * - * @return bool + * @return null|bool */ public function getSuperscript() { @@ -377,7 +377,7 @@ class Font extends Supervisor /** * Get Subscript. * - * @return bool + * @return null|bool */ public function getSubscript() { @@ -411,7 +411,7 @@ class Font extends Supervisor /** * Get Underline. * - * @return string + * @return null|string */ public function getUnderline() { @@ -451,7 +451,7 @@ class Font extends Supervisor /** * Get Strikethrough. * - * @return bool + * @return null|bool */ public function getStrikethrough() { diff --git a/src/PhpSpreadsheet/Style/NumberFormat.php b/src/PhpSpreadsheet/Style/NumberFormat.php index b5cc05f4..6235d864 100644 --- a/src/PhpSpreadsheet/Style/NumberFormat.php +++ b/src/PhpSpreadsheet/Style/NumberFormat.php @@ -64,14 +64,14 @@ class NumberFormat extends Supervisor /** * Format Code. * - * @var string + * @var null|string */ protected $formatCode = self::FORMAT_GENERAL; /** * Built-in format Code. * - * @var string + * @var false|int */ protected $builtInFormatCode = 0; @@ -150,7 +150,7 @@ class NumberFormat extends Supervisor /** * Get Format Code. * - * @return string + * @return null|string */ public function getFormatCode() { @@ -190,7 +190,7 @@ class NumberFormat extends Supervisor /** * Get Built-In Format Code. * - * @return int + * @return false|int */ public function getBuiltInFormatCode() { diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter.php b/src/PhpSpreadsheet/Worksheet/AutoFilter.php index d8912b21..1a710e40 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter.php @@ -14,7 +14,7 @@ class AutoFilter /** * Autofilter Worksheet. * - * @var Worksheet + * @var null|Worksheet */ private $workSheet; @@ -47,7 +47,7 @@ class AutoFilter /** * Get AutoFilter Parent Worksheet. * - * @return Worksheet + * @return null|Worksheet */ public function getParent() { @@ -791,10 +791,10 @@ class AutoFilter if ($ruleOperator === AutoFilter\Column\Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) { $ruleValue = floor($ruleValue * ($dataRowCount / 100)); } - if ($ruleValue < 1) { + if (!is_array($ruleValue) && $ruleValue < 1) { $ruleValue = 1; } - if ($ruleValue > 500) { + if (!is_array($ruleValue) && $ruleValue > 500) { $ruleValue = 500; } diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php index 09584a7a..8ec0ca3b 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column.php @@ -49,7 +49,7 @@ class Column /** * Autofilter. * - * @var AutoFilter + * @var null|AutoFilter */ private $parent; @@ -77,14 +77,14 @@ class Column /** * Autofilter Column Rules. * - * @var array of Column\Rule + * @var Column\Rule[] */ private $ruleset = []; /** * Autofilter Column Dynamic Attributes. * - * @var array of mixed + * @var mixed[] */ private $attributes = []; @@ -133,7 +133,7 @@ class Column /** * Get this Column's AutoFilter Parent. * - * @return AutoFilter + * @return null|AutoFilter */ public function getParent() { @@ -256,7 +256,7 @@ class Column * * @param string $pName Attribute Name * - * @return string + * @return null|string */ public function getAttribute($pName) { diff --git a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php index 1aacb0cb..330a1641 100644 --- a/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php +++ b/src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php @@ -217,7 +217,7 @@ class Rule /** * Autofilter Rule Value. * - * @var string + * @var string|string[] */ private $value = ''; @@ -276,7 +276,7 @@ class Rule /** * Get AutoFilter Rule Value. * - * @return string + * @return string|string[] */ public function getValue() { diff --git a/src/PhpSpreadsheet/Worksheet/BaseDrawing.php b/src/PhpSpreadsheet/Worksheet/BaseDrawing.php index be2f23df..5829671b 100644 --- a/src/PhpSpreadsheet/Worksheet/BaseDrawing.php +++ b/src/PhpSpreadsheet/Worksheet/BaseDrawing.php @@ -39,7 +39,7 @@ class BaseDrawing implements IComparable /** * Worksheet. * - * @var Worksheet + * @var null|Worksheet */ protected $worksheet; @@ -190,7 +190,7 @@ class BaseDrawing implements IComparable /** * Get Worksheet. * - * @return Worksheet + * @return null|Worksheet */ public function getWorksheet() { @@ -330,7 +330,7 @@ class BaseDrawing implements IComparable // Resize proportional? if ($this->resizeProportional && $pValue != 0) { $ratio = $this->height / ($this->width != 0 ? $this->width : 1); - $this->height = round($ratio * $pValue); + $this->height = (int) round($ratio * $pValue); } // Set width @@ -361,7 +361,7 @@ class BaseDrawing implements IComparable // Resize proportional? if ($this->resizeProportional && $pValue != 0) { $ratio = $this->width / ($this->height != 0 ? $this->height : 1); - $this->width = round($ratio * $pValue); + $this->width = (int) round($ratio * $pValue); } // Set height @@ -392,10 +392,10 @@ class BaseDrawing implements IComparable $yratio = $height / ($this->height != 0 ? $this->height : 1); if ($this->resizeProportional && !($width == 0 || $height == 0)) { if (($xratio * $this->height) < $height) { - $this->height = ceil($xratio * $this->height); + $this->height = (int) ceil($xratio * $this->height); $this->width = $width; } else { - $this->width = ceil($yratio * $this->width); + $this->width = (int) ceil($yratio * $this->width); $this->height = $height; } } else { diff --git a/src/PhpSpreadsheet/Worksheet/CellIterator.php b/src/PhpSpreadsheet/Worksheet/CellIterator.php index e0f35b64..31f6ae65 100644 --- a/src/PhpSpreadsheet/Worksheet/CellIterator.php +++ b/src/PhpSpreadsheet/Worksheet/CellIterator.php @@ -25,6 +25,7 @@ abstract class CellIterator implements Iterator */ public function __destruct() { + // @phpstan-ignore-next-line $this->worksheet = null; } diff --git a/src/PhpSpreadsheet/Worksheet/Column.php b/src/PhpSpreadsheet/Worksheet/Column.php index 763806a0..8abbabe5 100644 --- a/src/PhpSpreadsheet/Worksheet/Column.php +++ b/src/PhpSpreadsheet/Worksheet/Column.php @@ -36,6 +36,7 @@ class Column */ public function __destruct() { + // @phpstan-ignore-next-line $this->parent = null; } diff --git a/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php b/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php index 1390214e..65772114 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php @@ -18,7 +18,7 @@ class ColumnCellIterator extends CellIterator /** * Column index. * - * @var string + * @var int */ private $columnIndex; diff --git a/src/PhpSpreadsheet/Worksheet/ColumnIterator.php b/src/PhpSpreadsheet/Worksheet/ColumnIterator.php index a7466881..0651a7a4 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnIterator.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnIterator.php @@ -57,6 +57,7 @@ class ColumnIterator implements Iterator */ public function __destruct() { + // @phpstan-ignore-next-line $this->worksheet = null; } diff --git a/src/PhpSpreadsheet/Worksheet/Drawing/Shadow.php b/src/PhpSpreadsheet/Worksheet/Drawing/Shadow.php index 01ffed94..0557c83c 100644 --- a/src/PhpSpreadsheet/Worksheet/Drawing/Shadow.php +++ b/src/PhpSpreadsheet/Worksheet/Drawing/Shadow.php @@ -52,7 +52,7 @@ class Shadow implements IComparable /** * Shadow alignment. * - * @var int + * @var string */ private $alignment; @@ -184,7 +184,7 @@ class Shadow implements IComparable /** * Get Shadow alignment. * - * @return int + * @return string */ public function getAlignment() { @@ -194,7 +194,7 @@ class Shadow implements IComparable /** * Set Shadow alignment. * - * @param int $pValue + * @param string $pValue * * @return $this */ diff --git a/src/PhpSpreadsheet/Worksheet/Iterator.php b/src/PhpSpreadsheet/Worksheet/Iterator.php index 93b0bb04..134b619a 100644 --- a/src/PhpSpreadsheet/Worksheet/Iterator.php +++ b/src/PhpSpreadsheet/Worksheet/Iterator.php @@ -29,14 +29,6 @@ class Iterator implements \Iterator $this->subject = $subject; } - /** - * Destructor. - */ - public function __destruct() - { - $this->subject = null; - } - /** * Rewind iterator. */ diff --git a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php index fb002114..cde23c96 100644 --- a/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php +++ b/src/PhpSpreadsheet/Worksheet/MemoryDrawing.php @@ -52,7 +52,6 @@ class MemoryDrawing extends BaseDrawing public function __construct() { // Initialise values - $this->imageResource = null; $this->renderingFunction = self::RENDERING_DEFAULT; $this->mimeType = self::MIMETYPE_DEFAULT; $this->uniqueName = md5(mt_rand(0, 9999) . time() . mt_rand(0, 9999)); diff --git a/src/PhpSpreadsheet/Worksheet/PageSetup.php b/src/PhpSpreadsheet/Worksheet/PageSetup.php index d1a22a7b..7f3f71dc 100644 --- a/src/PhpSpreadsheet/Worksheet/PageSetup.php +++ b/src/PhpSpreadsheet/Worksheet/PageSetup.php @@ -238,7 +238,7 @@ class PageSetup /** * Print area. * - * @var string + * @var null|string */ private $printArea; diff --git a/src/PhpSpreadsheet/Worksheet/Row.php b/src/PhpSpreadsheet/Worksheet/Row.php index cf935743..01053c39 100644 --- a/src/PhpSpreadsheet/Worksheet/Row.php +++ b/src/PhpSpreadsheet/Worksheet/Row.php @@ -36,6 +36,7 @@ class Row */ public function __destruct() { + // @phpstan-ignore-next-line $this->worksheet = null; } diff --git a/src/PhpSpreadsheet/Worksheet/RowIterator.php b/src/PhpSpreadsheet/Worksheet/RowIterator.php index 469c284c..7d49f1ac 100644 --- a/src/PhpSpreadsheet/Worksheet/RowIterator.php +++ b/src/PhpSpreadsheet/Worksheet/RowIterator.php @@ -50,14 +50,6 @@ class RowIterator implements Iterator $this->resetStart($startRow); } - /** - * Destructor. - */ - public function __destruct() - { - $this->subject = null; - } - /** * (Re)Set the start row and the current row pointer. * diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index f8b6a743..02d7692b 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -105,7 +105,7 @@ class Worksheet implements IComparable * * @var ArrayObject */ - private $chartCollection = []; + private $chartCollection; /** * Worksheet title. @@ -278,9 +278,9 @@ class Worksheet implements IComparable /** * Cached highest column. * - * @var string + * @var int */ - private $cachedHighestColumn = 'A'; + private $cachedHighestColumn = 1; /** * Cached highest row. @@ -313,7 +313,7 @@ class Worksheet implements IComparable /** * Tab color. * - * @var Color + * @var null|Color */ private $tabColor; @@ -383,9 +383,11 @@ class Worksheet implements IComparable { if ($this->cellCollection !== null) { $this->cellCollection->unsetWorksheetCells(); + // @phpstan-ignore-next-line $this->cellCollection = null; } // detach ourself from the workbook, so that it can then delete this worksheet successfully + // @phpstan-ignore-next-line $this->parent = null; } @@ -1039,7 +1041,7 @@ class Worksheet implements IComparable public function getHighestColumn($row = null) { if ($row == null) { - return $this->cachedHighestColumn; + return Coordinate::stringFromColumnIndex($this->cachedHighestColumn); } return $this->getHighestDataColumn($row); @@ -1252,11 +1254,12 @@ class Worksheet implements IComparable // Coordinates $aCoordinates = Coordinate::coordinateFromString($pCoordinate); - if (Coordinate::columnIndexFromString($this->cachedHighestColumn) < Coordinate::columnIndexFromString($aCoordinates[0])) { - $this->cachedHighestColumn = $aCoordinates[0]; + $aIndexes = Coordinate::indexesFromString($pCoordinate); + if ($this->cachedHighestColumn < $aIndexes[0]) { + $this->cachedHighestColumn = $aIndexes[0]; } - if ($aCoordinates[1] > $this->cachedHighestRow) { - $this->cachedHighestRow = $aCoordinates[1]; + if ($aIndexes[1] > $this->cachedHighestRow) { + $this->cachedHighestRow = $aIndexes[1]; } // Cell needs appropriate xfIndex from dimensions records @@ -1377,8 +1380,9 @@ class Worksheet implements IComparable } $this->columnDimensions[$pColumn] = new ColumnDimension($pColumn); - if (Coordinate::columnIndexFromString($this->cachedHighestColumn) < Coordinate::columnIndexFromString($pColumn)) { - $this->cachedHighestColumn = $pColumn; + $columnIndex = Coordinate::columnIndexFromString($pColumn); + if ($this->cachedHighestColumn < $columnIndex) { + $this->cachedHighestColumn = $columnIndex; } } @@ -1987,7 +1991,7 @@ class Worksheet implements IComparable /** * Get the default position of the right bottom pane. * - * @return int + * @return null|string */ public function getTopLeftCell() { @@ -2677,9 +2681,9 @@ class Worksheet implements IComparable // Cache values if ($highestColumn < 1) { - $this->cachedHighestColumn = 'A'; + $this->cachedHighestColumn = 1; } else { - $this->cachedHighestColumn = Coordinate::stringFromColumnIndex($highestColumn); + $this->cachedHighestColumn = $highestColumn; } $this->cachedHighestRow = $highestRow; @@ -2905,7 +2909,6 @@ class Worksheet implements IComparable public function resetTabColor() { $this->tabColor = null; - $this->tabColor = null; return $this; } @@ -2935,6 +2938,7 @@ class Worksheet implements IComparable */ public function __clone() { + // @phpstan-ignore-next-line foreach ($this as $key => $val) { if ($key == 'parent') { continue; diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index 60612737..4ee94114 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -37,7 +37,7 @@ class Html extends BaseWriter /** * Sheet index to write. * - * @var int + * @var null|int */ private $sheetIndex = 0; @@ -735,7 +735,7 @@ class Html extends BaseWriter if ($chartCoordinates['cell'] == $coordinates) { $chartFileName = File::sysGetTempDir() . '/' . uniqid('', true) . '.png'; if (!$chart->render($chartFileName)) { - return; + return ''; } $html .= PHP_EOL; diff --git a/src/PhpSpreadsheet/Writer/Pdf.php b/src/PhpSpreadsheet/Writer/Pdf.php index 87220458..36f3966d 100644 --- a/src/PhpSpreadsheet/Writer/Pdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf.php @@ -165,7 +165,7 @@ abstract class Pdf extends Html /** * Set Paper Size. * - * @param string $pValue Paper size see PageSetup::PAPERSIZE_* + * @param int $pValue Paper size see PageSetup::PAPERSIZE_* * * @return self */ diff --git a/src/PhpSpreadsheet/Writer/Xls.php b/src/PhpSpreadsheet/Writer/Xls.php index 1ee52bdf..a1b477bf 100644 --- a/src/PhpSpreadsheet/Writer/Xls.php +++ b/src/PhpSpreadsheet/Writer/Xls.php @@ -81,14 +81,14 @@ class Xls extends BaseWriter /** * Basic OLE object summary information. * - * @var array + * @var string */ private $summaryInformation; /** * Extended OLE object document summary information. * - * @var array + * @var string */ private $documentSummaryInformation; @@ -727,6 +727,7 @@ class Xls extends BaseWriter } elseif ($dataProp['type']['data'] == 0x1E) { // null-terminated string prepended by dword string length // Null-terminated string $dataProp['data']['data'] .= chr(0); + // @phpstan-ignore-next-line ++$dataProp['data']['length']; // Complete the string with null string for being a %4 $dataProp['data']['length'] = $dataProp['data']['length'] + ((4 - $dataProp['data']['length'] % 4) == 4 ? 0 : (4 - $dataProp['data']['length'] % 4)); @@ -744,6 +745,7 @@ class Xls extends BaseWriter } else { $dataSection_Content .= $dataProp['data']['data']; + // @phpstan-ignore-next-line $dataSection_Content_Offset += 4 + $dataProp['data']['length']; } } diff --git a/src/PhpSpreadsheet/Writer/Xls/BIFFwriter.php b/src/PhpSpreadsheet/Writer/Xls/BIFFwriter.php index 84e27d0d..4a7e0656 100644 --- a/src/PhpSpreadsheet/Writer/Xls/BIFFwriter.php +++ b/src/PhpSpreadsheet/Writer/Xls/BIFFwriter.php @@ -49,7 +49,7 @@ class BIFFwriter /** * The string containing the data of the BIFF stream. * - * @var string + * @var null|string */ public $_data; diff --git a/src/PhpSpreadsheet/Writer/Xls/Font.php b/src/PhpSpreadsheet/Writer/Xls/Font.php index 9cb31ead..1266cf24 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Font.php +++ b/src/PhpSpreadsheet/Writer/Xls/Font.php @@ -119,7 +119,7 @@ class Font /** * Map of BIFF2-BIFF8 codes for underline styles. * - * @var array of int + * @var int[] */ private static $mapUnderline = [ \PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE => 0x00, diff --git a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php index fdc05b85..7051ab2d 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Worksheet.php +++ b/src/PhpSpreadsheet/Writer/Xls/Worksheet.php @@ -95,7 +95,7 @@ class Worksheet extends BIFFwriter /** * Whether to use outline. * - * @var int + * @var bool */ private $outlineOn; @@ -244,10 +244,10 @@ class Worksheet extends BIFFwriter $this->printHeaders = 0; - $this->outlineStyle = 0; - $this->outlineBelow = 1; - $this->outlineRight = 1; - $this->outlineOn = 1; + $this->outlineStyle = false; + $this->outlineBelow = true; + $this->outlineRight = true; + $this->outlineOn = true; $this->fontHashIndex = []; @@ -594,15 +594,13 @@ class Worksheet extends BIFFwriter } /** - * Retrieves data from memory in one chunk, or from disk in $buffer + * Retrieves data from memory in one chunk, or from disk * sized chunks. * * @return string The data */ public function getData() { - $buffer = 4096; - // Return data stored in memory if (isset($this->_data)) { $tmp = $this->_data; @@ -612,7 +610,7 @@ class Worksheet extends BIFFwriter } // No data to return - return false; + return ''; } /** @@ -640,11 +638,6 @@ class Worksheet extends BIFFwriter $this->outlineBelow = $symbols_below; $this->outlineRight = $symbols_right; $this->outlineStyle = $auto_style; - - // Ensure this is a boolean vale for Window2 - if ($this->outlineOn) { - $this->outlineOn = 1; - } } /** @@ -926,20 +919,14 @@ class Worksheet extends BIFFwriter * The hyperlink can be to a http, ftp, mail, internal sheet (not yet), or external * directory url. * - * Returns 0 : normal termination - * -2 : row or column out of range - * -3 : long string truncated to 255 chars - * * @param int $row Row * @param int $col Column * @param string $url URL string - * - * @return int */ - private function writeUrl($row, $col, $url) + private function writeUrl($row, $col, $url): void { // Add start row and col to arg list - return $this->writeUrlRange($row, $col, $row, $col, $url); + $this->writeUrlRange($row, $col, $row, $col, $url); } /** @@ -954,21 +941,19 @@ class Worksheet extends BIFFwriter * @param int $col2 End column * @param string $url URL string * - * @return int - * * @see writeUrl() */ - public function writeUrlRange($row1, $col1, $row2, $col2, $url) + private function writeUrlRange($row1, $col1, $row2, $col2, $url): void { // Check for internal/external sheet links or default to web link if (preg_match('[^internal:]', $url)) { - return $this->writeUrlInternal($row1, $col1, $row2, $col2, $url); + $this->writeUrlInternal($row1, $col1, $row2, $col2, $url); } if (preg_match('[^external:]', $url)) { - return $this->writeUrlExternal($row1, $col1, $row2, $col2, $url); + $this->writeUrlExternal($row1, $col1, $row2, $col2, $url); } - return $this->writeUrlWeb($row1, $col1, $row2, $col2, $url); + $this->writeUrlWeb($row1, $col1, $row2, $col2, $url); } /** @@ -982,14 +967,11 @@ class Worksheet extends BIFFwriter * @param int $col2 End column * @param string $url URL string * - * @return int - * * @see writeUrl() */ - public function writeUrlWeb($row1, $col1, $row2, $col2, $url) + public function writeUrlWeb($row1, $col1, $row2, $col2, $url): void { $record = 0x01B8; // Record identifier - $length = 0x00000; // Bytes to follow // Pack the undocumented parts of the hyperlink stream $unknown1 = pack('H*', 'D0C9EA79F9BACE118C8200AA004BA90B02000000'); @@ -1014,8 +996,6 @@ class Worksheet extends BIFFwriter // Write the packed data $this->append($header . $data . $unknown1 . $options . $unknown2 . $url_len . $url); - - return 0; } /** @@ -1027,14 +1007,11 @@ class Worksheet extends BIFFwriter * @param int $col2 End column * @param string $url URL string * - * @return int - * * @see writeUrl() */ - public function writeUrlInternal($row1, $col1, $row2, $col2, $url) + private function writeUrlInternal($row1, $col1, $row2, $col2, $url): void { $record = 0x01B8; // Record identifier - $length = 0x00000; // Bytes to follow // Strip URL type $url = preg_replace('/^internal:/', '', $url); @@ -1063,8 +1040,6 @@ class Worksheet extends BIFFwriter // Write the packed data $this->append($header . $data . $unknown1 . $options . $url_len . $url); - - return 0; } /** @@ -1080,16 +1055,14 @@ class Worksheet extends BIFFwriter * @param int $col2 End column * @param string $url URL string * - * @return int - * * @see writeUrl() */ - public function writeUrlExternal($row1, $col1, $row2, $col2, $url) + private function writeUrlExternal($row1, $col1, $row2, $col2, $url): void { // Network drives are different. We will handle them separately // MS/Novell network drives and shares start with \\ if (preg_match('[^external:\\\\]', $url)) { - return; //($this->writeUrlExternal_net($row1, $col1, $row2, $col2, $url, $str, $format)); + return; } $record = 0x01B8; // Record identifier @@ -1165,8 +1138,6 @@ class Worksheet extends BIFFwriter // Write the packed data $this->append($header . $data); - - return 0; } /** diff --git a/src/PhpSpreadsheet/Writer/Xls/Xf.php b/src/PhpSpreadsheet/Writer/Xls/Xf.php index eca3d8e0..6f1d1cb2 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Xf.php +++ b/src/PhpSpreadsheet/Writer/Xls/Xf.php @@ -362,7 +362,7 @@ class Xf /** * Map of BIFF2-BIFF8 codes for border styles. * - * @var array of int + * @var int[] */ private static $mapBorderStyles = [ Border::BORDER_NONE => 0x00, @@ -396,7 +396,7 @@ class Xf /** * Map of BIFF2-BIFF8 codes for fill types. * - * @var array of int + * @var int[] */ private static $mapFillTypes = [ Fill::FILL_NONE => 0x00, @@ -437,7 +437,7 @@ class Xf /** * Map of BIFF2-BIFF8 codes for horizontal alignment. * - * @var array of int + * @var int[] */ private static $mapHAlignments = [ Alignment::HORIZONTAL_GENERAL => 0, @@ -464,7 +464,7 @@ class Xf /** * Map of BIFF2-BIFF8 codes for vertical alignment. * - * @var array of int + * @var int[] */ private static $mapVAlignments = [ Alignment::VERTICAL_TOP => 0, diff --git a/src/PhpSpreadsheet/Writer/Xlsx.php b/src/PhpSpreadsheet/Writer/Xlsx.php index 61351ed8..27ceb559 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx.php +++ b/src/PhpSpreadsheet/Writer/Xlsx.php @@ -200,12 +200,19 @@ class Xlsx extends BaseWriter $this->writerPartWorksheet = new Worksheet($this); // Set HashTable variables + // @phpstan-ignore-next-line $this->bordersHashTable = new HashTable(); + // @phpstan-ignore-next-line $this->drawingHashTable = new HashTable(); + // @phpstan-ignore-next-line $this->fillHashTable = new HashTable(); + // @phpstan-ignore-next-line $this->fontHashTable = new HashTable(); + // @phpstan-ignore-next-line $this->numFmtHashTable = new HashTable(); + // @phpstan-ignore-next-line $this->styleHashTable = new HashTable(); + // @phpstan-ignore-next-line $this->stylesConditionalHashTable = new HashTable(); } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php b/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php index bcbc2379..6332a34d 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/DocProps.php @@ -170,13 +170,13 @@ class DocProps extends WriterPart /** * Write docProps/custom.xml to XML format. * - * @return string XML Output + * @return null|string XML Output */ public function writeDocPropsCustom(Spreadsheet $spreadsheet) { $customPropertyList = $spreadsheet->getProperties()->getCustomProperties(); if (empty($customPropertyList)) { - return; + return null; } // Create XML writer diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Theme.php b/src/PhpSpreadsheet/Writer/Xlsx/Theme.php index dfde302c..99177292 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Theme.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Theme.php @@ -10,7 +10,7 @@ class Theme extends WriterPart /** * Map of Major fonts to write. * - * @var array of string + * @var string[] */ private static $majorFonts = [ 'Jpan' => 'MS Pゴシック', @@ -48,7 +48,7 @@ class Theme extends WriterPart /** * Map of Minor fonts to write. * - * @var array of string + * @var string[] */ private static $minorFonts = [ 'Jpan' => 'MS Pゴシック', @@ -86,7 +86,7 @@ class Theme extends WriterPart /** * Map of core colours. * - * @var array of string + * @var string[] */ private static $colourScheme = [ 'dk2' => '1F497D', diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php index bc3a3918..af96c18e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php @@ -22,11 +22,6 @@ class ImConjugateTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMCONJUGATE * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php index 693f0bab..c00bafda 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php @@ -22,11 +22,6 @@ class ImCosTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMCOS * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php index ae035fef..6f84217a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php @@ -22,11 +22,6 @@ class ImCoshTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMCOSH * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php index 8b888b3f..cbadfd8a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php @@ -22,11 +22,6 @@ class ImCotTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMCOT * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php index 5a08c0b6..65782e32 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php @@ -22,11 +22,6 @@ class ImCscTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMCSC * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php index a95a4eaf..ef1c06ea 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php @@ -22,11 +22,6 @@ class ImCschTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMCSCH * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php index 2bc91619..0943f408 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php @@ -22,11 +22,6 @@ class ImDivTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMDIV * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php index 7debbc9c..5f5edfd3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php @@ -22,11 +22,6 @@ class ImExpTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMEXP * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php index 3e270975..36ca116a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php @@ -22,11 +22,6 @@ class ImLnTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMLN * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php index 2a4db7fb..9a37d85c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php @@ -22,11 +22,6 @@ class ImLog10Test extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMLOG10 * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php index 53b302dd..f0d853ba 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php @@ -22,11 +22,6 @@ class ImLog2Test extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMLOG2 * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php index 41e52878..4493515c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php @@ -22,11 +22,6 @@ class ImPowerTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMPOWER * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php index 43495739..395153ed 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php @@ -22,11 +22,6 @@ class ImProductTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMPRODUCT * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php index e785d3ac..bd9c6df0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php @@ -22,11 +22,6 @@ class ImSecTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSEC * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php index 22cb6fae..b81e0305 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php @@ -22,11 +22,6 @@ class ImSechTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSECH * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php index dd797a35..d83980e0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php @@ -22,11 +22,6 @@ class ImSinTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSIN * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php index 4174d1c0..107c0949 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php @@ -22,11 +22,6 @@ class ImSinhTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSINH * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php index 091b11c5..c8c83e10 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php @@ -22,11 +22,6 @@ class ImSqrtTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSQRT * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php index 79286120..b2b8394e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php @@ -22,11 +22,6 @@ class ImSubTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSUB * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php index 8abc3638..872c73c8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php @@ -22,11 +22,6 @@ class ImSumTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMSUM * diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php index 57b23815..9bf6b66c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php @@ -22,11 +22,6 @@ class ImTanTest extends TestCase $this->complexAssert = new ComplexAssert(); } - protected function tearDown(): void - { - $this->complexAssert = null; - } - /** * @dataProvider providerIMTAN * diff --git a/tests/PhpSpreadsheetTests/SettingsTest.php b/tests/PhpSpreadsheetTests/SettingsTest.php index 92f3bb1f..7641f3da 100644 --- a/tests/PhpSpreadsheetTests/SettingsTest.php +++ b/tests/PhpSpreadsheetTests/SettingsTest.php @@ -8,7 +8,7 @@ use PHPUnit\Framework\TestCase; class SettingsTest extends TestCase { /** - * @var string + * @var bool */ protected $prevValue; From 89aa7e6fcd45db67e5311e9304f6198e83a42dc7 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Sun, 11 Apr 2021 16:56:36 +0900 Subject: [PATCH 178/187] Introduce PHPstan baseline --- phpstan-baseline.neon | 18142 ++++++++++++++++++++++++++++++++++++++++ phpstan.neon.dist | 5 +- 2 files changed, 18146 insertions(+), 1 deletion(-) create mode 100644 phpstan-baseline.neon diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 00000000..c80e5931 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,18142 @@ +parameters: + ignoreErrors: + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$returnArrayAsType has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$calculationCache type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$branchPruningEnabled has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$operators type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$binaryOperators type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$cellStack has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$cyclicFormulaCell has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$localeFunctions has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$phpSpreadsheetFunctions has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$controlFunctions has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Binary operation \"\\-\" between 0 and string\\|false results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$spreadsheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#3 \\$formula of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:translateSeparator\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$functionReplaceFromExcel has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$functionReplaceToLocale has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:_translateFormulaToLocale\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:_translateFormulaToLocale\\(\\) has parameter \\$formula with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$str of function preg_quote expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$functionReplaceFromLocale has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$functionReplaceToExcel has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:_translateFormulaToEnglish\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:_translateFormulaToEnglish\\(\\) has parameter \\$formula with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$str of function trim expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:localeFunc\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:localeFunc\\(\\) has parameter \\$function with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 6 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:parseFormula\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:checkMatrixOperands\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getMatrixDimensions\\(\\) has parameter \\$matrix with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$operatorAssociativity has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$comparisonOperators has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$operatorPrecedence has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Strict comparison using \\=\\=\\= between mixed and null will always evaluate to false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$haystack of function stripos expects string, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:dataTestReference\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:dataTestReference\\(\\) has parameter \\$operandData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getColumn\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$str of function trim expects string, null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getCoordinate\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method has\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:attach\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells, PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method attach\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:validateBinaryOperand\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:validateBinaryOperand\\(\\) has parameter \\$operand with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:validateBinaryOperand\\(\\) has parameter \\$stack with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:executeArrayComparison\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:strCaseReverse\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:raiseFormulaError\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:raiseFormulaError\\(\\) has parameter \\$errorMessage with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method cellExists\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#2 \\$pSheet of static method PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\:\\:resolveName\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet, PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getHighestRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Cannot call method getHighestColumn\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getFunctions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getImplementedFunctionNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:addCellReference\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:addCellReference\\(\\) has parameter \\$functionCall with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:addCellReference\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getUnusedBranchStoreKey\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getTokensAsString\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getTokensAsString\\(\\) has parameter \\$tokens with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Calculation.php + + - + message: "#^Parameter \\#2 \\$field of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DCountA\\:\\:evaluate\\(\\) expects int\\|string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DMAX\\(\\) should return float but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DMIN\\(\\) should return float but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DPRODUCT\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DSTDEV\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DSTDEVP\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DSUM\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DVAR\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\:\\:DVARP\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:evaluate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:evaluate\\(\\) has parameter \\$criteria with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:evaluate\\(\\) has parameter \\$database with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:evaluate\\(\\) has parameter \\$field with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:getFilteredColumn\\(\\) has parameter \\$criteria with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:getFilteredColumn\\(\\) has parameter \\$database with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:getFilteredColumn\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:buildQuery\\(\\) has parameter \\$criteria with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:buildQuery\\(\\) has parameter \\$criteriaNames with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:buildCondition\\(\\) has parameter \\$criterion with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) has parameter \\$criteria with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) has parameter \\$database with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) has parameter \\$fields with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:processCondition\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:processCondition\\(\\) has parameter \\$dataValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:processCondition\\(\\) has parameter \\$fields with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTime\\:\\:NETWORKDAYS\\(\\) has parameter \\$dateArgs with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTime.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTime\\:\\:WORKDAY\\(\\) has parameter \\$dateArgs with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTime.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Parameter \\#1 \\$PHPDateArray of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:finalResults\\(\\) expects array\\|false, array\\|bool given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:t1ToString\\(\\) has parameter \\$t1 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:setUpArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Parameter \\#1 \\$testVal1 of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustYear\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Parameter \\#2 \\$testVal2 of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustYear\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:finalResults\\(\\) has parameter \\$PHPDateArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php + + - + message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:testStringAsNumeric\\(\\) expects string, float\\|int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Datefunc.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Day\\:\\:weirdCondition\\(\\) has parameter \\$dateValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Day.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustDateByMonths\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustDateByMonths\\(\\) has parameter \\$adjustmentMonths with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustDateByMonths\\(\\) has parameter \\$dateValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:returnIn3FormatsArray\\(\\) has parameter \\$dateArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php + + - + message: "#^Parameter \\#1 \\$excelTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:excelToTimestamp\\(\\) expects float\\|int, bool\\|float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:validateNumericNull\\(\\) should return float\\|int but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\IsoWeekNum\\:\\:apparentBug\\(\\) has parameter \\$dateValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/IsoWeekNum.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\NetworkDays\\:\\:funcNetworkDays\\(\\) has parameter \\$dateArgs with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\NetworkDays\\:\\:applySign\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/NetworkDays.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Time\\:\\:toIntWithNullBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Time.php + + - + message: "#^Cannot access offset 0 on array\\\\|false\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php + + - + message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, array\\\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/TimeValue.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WeekDay\\:\\:validateStyle\\(\\) has parameter \\$style with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:funcWorkDay\\(\\) has parameter \\$dateArgs with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:incrementing\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Binary operation \"\\-\" between 7 and int\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Binary operation \"\\-\" between 7 and int\\<5, max\\>\\|string results in an error\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:incrementingArray\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:decrementing\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Binary operation \"\\-\" between 4 and int\\<5, max\\>\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:decrementingArray\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php + + - + message: "#^Binary operation \"\\-\" between int\\|string and int\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php + + - + message: "#^Binary operation \"\\*\" between 100 and int\\|string results in an error\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/DateTimeExcel/YearFrac.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engine\\\\Logger\\:\\:writeDebugLog\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engine/Logger.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:BITLSHIFT\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:BITRSHIFT\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:getConversionGroups\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:getConversionGroupUnits\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:getConversionGroupUnitDetails\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselI\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselI.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselI\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselI.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselI.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:besselj2a\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:besselj2b\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:besselK2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselY\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselY.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselY\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselY.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BesselY.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Compare\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Compare.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Compare\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Compare.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Compare.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Complex\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Complex\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BitWise\\:\\:splitNumber\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BitWise.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BitWise\\:\\:validateBitwiseArgument\\(\\) never returns int so it can be removed from the return typehint\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BitWise.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BitWise.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\<0, 281474976710655\\>\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/BitWise.php + + - + message: "#^Parameter \\#1 \\$power of method Complex\\\\Complex\\:\\:pow\\(\\) expects float\\|int, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ComplexFunctions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertBase\\:\\:validateValue\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertBase\\:\\:validatePlaces\\(\\) has parameter \\$places with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getConversionCategories\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getConversionCategoryUnits\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getConversionCategoryUnitDetails\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getUOMDetails\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:resolveTemperatureSynonyms\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Erf\\:\\:\\$twoSqrtPi has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Erf\\:\\:erfValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Erf\\:\\:erfValue\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php + + - + message: "#^Binary operation \"\\-\" between 1 and float\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/Erf.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ErfC\\:\\:\\$oneSqrtPi has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ErfC\\:\\:erfcValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ErfC\\:\\:erfcValue\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php + + - + message: "#^Binary operation \"\\-\" between 2 and float\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Engineering/ErfC.php + + - + message: "#^Parameter \\#1 \\$callback of function set_error_handler expects \\(callable\\(int, string, string, int, array\\)\\: bool\\)\\|null, array\\('PhpOffice\\\\\\\\PhpSpreadsheet\\\\\\\\Calculation\\\\\\\\Exception', 'errorHandlerCallback'\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/ExceptionHandler.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\:\\:ISPMT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\:\\:ISPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\:\\:NPV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial.php + + - + message: "#^Result of && is always true\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Financial.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:schedulePayment\\(\\) has no return typehint 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 no return typehint 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 typehint 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 typehint 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 typehint 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 typehint 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 typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Binary operation \"\\*\" between float\\|string and int results in an error\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Binary operation \"\\*\" between float\\|string and int\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$next with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSalvage\\(\\) has parameter \\$salvage with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateLife\\(\\) has parameter \\$life with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validatePeriod\\(\\) has parameter \\$period with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMonth\\(\\) has parameter \\$month with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFactor\\(\\) has parameter \\$factor with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:price\\(\\) should return float\\|string but returns float\\|int\\<0, max\\>\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\InterestAndPrincipal\\:\\:\\$interest has no typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.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: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:bothNegAndPos\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:bothNegAndPos\\(\\) has parameter \\$neg with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:bothNegAndPos\\(\\) has parameter \\$pos with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart1\\(\\) has parameter \\$dates with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart1\\(\\) has parameter \\$values with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart2\\(\\) has parameter \\$values with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart3\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart3\\(\\) has parameter \\$dates with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart3\\(\\) has parameter \\$values with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart3\\(\\) has parameter \\$x1 with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xirrPart3\\(\\) has parameter \\$x2 with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) has parameter \\$dates with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) has parameter \\$ordered with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) has parameter \\$rate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:xnpvOrdered\\(\\) has parameter \\$values with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:validateXnpv\\(\\) has parameter \\$dates with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:validateXnpv\\(\\) has parameter \\$rate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/NonPeriodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Variable\\\\NonPeriodic\\:\\:validateXnpv\\(\\) has parameter \\$values with no typehint specified\\.$#" + 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateIssueDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateIssueDate\\(\\) has parameter \\$issue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSecurityPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSecurityPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateRate\\(\\) has parameter \\$rate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateParValue\\(\\) has parameter \\$parValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validatePrice\\(\\) has parameter \\$price with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateYield\\(\\) has parameter \\$yield with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateRedemption\\(\\) has parameter \\$redemption with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateDiscount\\(\\) has parameter \\$discount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateIssueDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateIssueDate\\(\\) has parameter \\$issue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSecurityPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSecurityPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateRate\\(\\) has parameter \\$rate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateParValue\\(\\) has parameter \\$parValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validatePrice\\(\\) has parameter \\$price with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateYield\\(\\) has parameter \\$yield with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateRedemption\\(\\) has parameter \\$redemption with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateDiscount\\(\\) has parameter \\$discount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateIssueDate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateIssueDate\\(\\) has parameter \\$issue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSecurityPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSecurityPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateRate\\(\\) has parameter \\$rate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateParValue\\(\\) has parameter \\$parValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validatePrice\\(\\) has parameter \\$price with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateYield\\(\\) has parameter \\$yield with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateRedemption\\(\\) has parameter \\$redemption with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateDiscount\\(\\) has parameter \\$discount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + + - + message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/FormulaParser.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken\\|null\\.$#" + count: 5 + path: src/PhpSpreadsheet/Calculation/FormulaParser.php + + - + message: "#^Cannot call method setTokenSubType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken\\|null\\.$#" + count: 5 + path: src/PhpSpreadsheet/Calculation/FormulaParser.php + + - + message: "#^Cannot call method getTokenType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken\\|null\\.$#" + count: 9 + path: src/PhpSpreadsheet/Calculation/FormulaParser.php + + - + message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/FormulaParser.php + + - + message: "#^Cannot call method getTokenSubType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\FormulaToken\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Calculation/FormulaParser.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:\\$errorCodes type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isMatrixValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isMatrixValue\\(\\) has parameter \\$idx with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isValue\\(\\) has parameter \\$idx with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isCellValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isCellValue\\(\\) has parameter \\$idx with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:ifCondition\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:ifCondition\\(\\) has parameter \\$condition with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:operandSpecialHandling\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:operandSpecialHandling\\(\\) has parameter \\$operand with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:flattenArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:flattenArrayIndexed\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Cannot call method isFormula\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Functions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\MakeMatrix\\:\\:make\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\MakeMatrix\\:\\:make\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:wildcard\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:compare\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Internal/WildcardMatch.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\\\\Logical\\\\Operations\\:\\:countTrueValues\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Logical/Operations.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:COLUMN\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:COLUMNS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:ROW\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:ROWS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:INDIRECT\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:INDIRECT\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:OFFSET\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:OFFSET\\(\\) should return array\\|string but returns array\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:CHOOSE\\(\\) has parameter \\$chooseArgs with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Call to function is_bool\\(\\) with float\\|int\\|\\(string&numeric\\) will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:TRANSPOSE\\(\\) has parameter \\$matrixData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:TRANSPOSE\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Cannot call method isFormula\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Address\\:\\:sheetName\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Address.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:MATCH\\(\\) should return int\\|string but returns float\\|int\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchFirstValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchFirstValue\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchFirstValue\\(\\) has parameter \\$lookupValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has parameter \\$keySet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchLargestValue\\(\\) has parameter \\$lookupValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchSmallestValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchSmallestValue\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:matchSmallestValue\\(\\) has parameter \\$lookupValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:validateLookupValue\\(\\) has parameter \\$lookupValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:validateMatchType\\(\\) has parameter \\$matchType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:validateLookupArray\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:prepareLookupArray\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:prepareLookupArray\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\ExcelMatch\\:\\:prepareLookupArray\\(\\) has parameter \\$matchType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/ExcelMatch.php + + - + message: "#^Binary operation \"\\-\" between int\\|string and 1 results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\HLookup\\:\\:hLookupSearch\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\HLookup\\:\\:hLookupSearch\\(\\) has parameter \\$column with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\HLookup\\:\\:hLookupSearch\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\HLookup\\:\\:hLookupSearch\\(\\) has parameter \\$lookupValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\HLookup\\:\\:hLookupSearch\\(\\) has parameter \\$notExactMatch with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:INDIRECT\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:INDIRECT\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:extractRequiredCells\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:extractWorksheet\\(\\) has parameter \\$cellAddress with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:extractWorksheet\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyLookupValues\\(\\) has parameter \\$lookupVector with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyLookupValues\\(\\) has parameter \\$resultVector with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyLookupValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has parameter \\$lookupVector with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has parameter \\$resultVector with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:rowCount\\(\\) has parameter \\$dataArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:columnCount\\(\\) has parameter \\$dataArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\LookupBase\\:\\:validateIndexLookup\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\LookupBase\\:\\:validateIndexLookup\\(\\) has parameter \\$index_number with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\LookupBase\\:\\:validateIndexLookup\\(\\) has parameter \\$lookup_array with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\LookupBase\\:\\:checkMatch\\(\\) has parameter \\$notExactMatch with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:transpose\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php + + - + message: "#^Parameter \\#3 \\$rowNum of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) expects int, float\\|int\\<0, max\\>\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) has parameter \\$matrix with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) has parameter \\$rowKeys with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:OFFSET\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:extractRequiredCells\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:extractWorksheet\\(\\) has parameter \\$cellAddress with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:extractWorksheet\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adjustEndCellColumnForWidth\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adjustEndCellColumnForWidth\\(\\) has parameter \\$columns with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adjustEndCellColumnForWidth\\(\\) has parameter \\$width with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adustEndCellRowForHeight\\(\\) has parameter \\$endCellRow with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adustEndCellRowForHeight\\(\\) has parameter \\$height with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adustEndCellRowForHeight\\(\\) has parameter \\$rows with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:COLUMN\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Parameter \\#1 \\$pString of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:columnIndexFromString\\(\\) expects string, string\\|null given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Cannot cast array\\|string to string\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:COLUMNS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:ROW\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Parameter \\#1 \\$low of function range expects float\\|int\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Parameter \\#2 \\$high of function range expects float\\|int\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:ROWS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php + + - + message: "#^Parameter \\#2 \\$cmp_function of function uasort expects callable\\(mixed, mixed\\)\\: int, array\\('self', 'vlookupSort'\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vlookupSort\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vlookupSort\\(\\) has parameter \\$a with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vlookupSort\\(\\) has parameter \\$b with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vLookupSearch\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vLookupSearch\\(\\) has parameter \\$column with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vLookupSearch\\(\\) has parameter \\$lookupArray with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vLookupSearch\\(\\) has parameter \\$lookupValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\VLookup\\:\\:vLookupSearch\\(\\) has parameter \\$notExactMatch with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/LookupRef/VLookup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:COMBIN\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:EVEN\\(\\) should return int\\|string but returns float\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:FACT\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:FACTDOUBLE\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MDETERM\\(\\) has parameter \\$matrixValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MINVERSE\\(\\) has parameter \\$matrixValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MINVERSE\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MMULT\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MMULT\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MMULT\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MOD\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:ODD\\(\\) should return int\\|string but returns float\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:SUMIFS\\(\\) should return float\\|string but returns float\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Arabic\\:\\:calculateArabic\\(\\) has parameter \\$roman with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Arabic\\:\\:strSplit\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php + + - + message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php + + - + message: "#^Parameter \\#1 \\$number of function base_convert expects string, int\\<0, 9007199254740991\\> given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Base.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Helpers\\:\\:validateNumericNullBool\\(\\) should return float\\|int but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Helpers\\:\\:validateNumericNullSubstitution\\(\\) should return float\\|int but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Lcm\\:\\:factors\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Lcm\\:\\:factors\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Lcm\\:\\:processPoweredFactors\\(\\) has parameter \\$allPoweredFactors with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Lcm\\:\\:processPoweredFactors\\(\\) has parameter \\$myPoweredFactors with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\MatrixFunctions\\:\\:funcMInverse\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\MatrixFunctions\\:\\:funcMMult\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\MatrixFunctions\\:\\:funcMUnit\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Roman\\:\\:romanCut\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Roman.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Roman\\:\\:romanCut\\(\\) has parameter \\$n with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Roman.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Roman\\:\\:romanCut\\(\\) has parameter \\$num with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Roman.php + + - + message: "#^Parameter \\#2 \\$precision of function round expects int, float\\|int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/MathTrig/RoundDown.php + + - + message: "#^Parameter \\#2 \\$precision of function round expects int, float\\|int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/MathTrig/RoundUp.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Subtotal\\:\\:filterHiddenArgs\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Subtotal\\:\\:filterHiddenArgs\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Subtotal\\:\\:filterHiddenArgs\\(\\) has parameter \\$cellReference with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Subtotal\\:\\:filterFormulaArgs\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Subtotal\\:\\:filterFormulaArgs\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Subtotal\\:\\:filterFormulaArgs\\(\\) has parameter \\$cellReference with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Parameter \\#1 \\$function of function call_user_func_array expects callable\\(\\)\\: mixed, array\\('PhpOffice…'\\|'PhpOffice…'\\|'PhpOffice…'\\|'PhpOffice…'\\|'PhpOffice…'\\|'PhpOffice…'\\|'PhpOffice…'\\|'PhpOffice…', string\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\SumSquares\\:\\:getCount\\(\\) has parameter \\$array1 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\SumSquares\\:\\:getCount\\(\\) has parameter \\$array2 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php + + - + message: "#^Parameter \\#1 \\$str of function rtrim expects string, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/MathTrig/Trunc.php + + - + message: "#^Binary operation \"\\-\" between float\\|int and float\\|string results in an error\\.$#" + count: 4 + path: src/PhpSpreadsheet/Calculation/Statistical.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:KURT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:LINEST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:LOGEST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical.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\\:\\:SKEW\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:filterArguments\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:filterArguments\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:modeCalc\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:modeCalc\\(\\) has parameter \\$data with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Confidence\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Confidence.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Confidence\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Confidence.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Confidence.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:percentileFilterValues\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:percentileFilterValues\\(\\) has parameter \\$dataSet with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:rankFilterValues\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:rankFilterValues\\(\\) has parameter \\$dataSet with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Permutations\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Permutations\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:filterTrendValues\\(\\) has parameter \\$array1 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:filterTrendValues\\(\\) has parameter \\$array2 with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:checkTrendArrays\\(\\) has parameter \\$array1 with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:checkTrendArrays\\(\\) has parameter \\$array2 with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateTrendArrays\\(\\) has parameter \\$xValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateTrendArrays\\(\\) has parameter \\$yValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:GROWTH\\(\\) should return array\\ but returns array\\\\>\\>\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:LINEST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:LOGEST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:TREND\\(\\) should return array\\ but returns array\\\\>\\>\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Trends.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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSet\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSetForValueRange\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSetForValueRange\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditions\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabase\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabase\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabaseWithValueRange\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabaseWithValueRange\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) has parameter \\$database with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:databaseFromRangeAndValue\\(\\) has parameter \\$range with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:databaseFromRangeAndValue\\(\\) has parameter \\$valueRange with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:databaseFromRangeAndValue\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:calculateInverse\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheP has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheQ has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheResult has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Binary operation \"\\*\" between int\\|string and \\(float\\|int\\) results in an error\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Binary operation \"\\-\" between 1 and float\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:test\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:test\\(\\) has parameter \\$actual with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:test\\(\\) has parameter \\$expected with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:inverseLeftTailCalculation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:inverseLeftTailCalculation\\(\\) has parameter \\$degrees with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:inverseLeftTailCalculation\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:pchisq\\(\\) has no return typehint 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 typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gammp\\(\\) has no return typehint 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 typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gser\\(\\) has no return typehint 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 typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:gcf\\(\\) has no return typehint 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 typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Binary operation \"\\*\" between int\\|string and int\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:inverseNcdf\\(\\) has no return typehint 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 typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:calculateDistribution\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:calculateInverse\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:\\$logGammaCacheResult has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:\\$logGammaCacheX has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma3\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:logGamma4\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/GammaBase.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\NewtonRaphson\\:\\:\\$callback has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\NewtonRaphson\\:\\:execute\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/NewtonRaphson.php + + - + message: "#^Binary operation \"\\-\" between 1 and float\\|string results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php + + - + message: "#^Binary operation \"\\-\" between float\\|string and float\\|int\\|\\(string&numeric\\) results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StandardNormal.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\MaxMinBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\MaxMinBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/MaxMinBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentAllowStrings\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentBooleans\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\VarianceBase\\:\\:datatypeAdjustmentBooleans\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Statistical/VarianceBase.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\:\\:TRIMNONPRINTABLE\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\:\\:TRIMSPACES\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\:\\:CONCATENATE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\:\\:SEARCHSENSITIVE\\(\\) should return string but returns int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\:\\:SEARCHINSENSITIVE\\(\\) should return string but returns int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\CharacterConvert\\:\\:character\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\CharacterConvert\\:\\:unicodeToOrd\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\CharacterConvert\\:\\:unicodeToOrd\\(\\) has parameter \\$character with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Cannot access offset 1 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Parameter \\#2 \\$data of function unpack expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\CharacterConvert\\:\\:convertBooleanValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\CharacterConvert\\:\\:convertBooleanValue\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/CharacterConvert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\Concatenate\\:\\:CONCATENATE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Concatenate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\Concatenate\\:\\:convertBooleanValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Concatenate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\Concatenate\\:\\:convertBooleanValue\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Concatenate.php + + - + message: "#^Parameter \\#3 \\$length of function mb_substr expects int\\|null, float\\|int\\<0, max\\>\\|string given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Calculation/TextData/Extract.php + + - + message: "#^Parameter \\#2 \\$start of function mb_substr expects int, float\\|int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/TextData/Extract.php + + - + message: "#^Parameter \\#1 \\$number of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Mround\\:\\:funcMround\\(\\) expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Format.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Format.php + + - + message: "#^Parameter \\#1 \\$number of function round expects float, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Format.php + + - + message: "#^Cannot cast array\\|float\\|int\\|string to float\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Format.php + + - + message: "#^Parameter \\#3 \\$offset of function mb_strpos expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Search.php + + - + message: "#^Parameter \\#3 \\$offset of function mb_stripos expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Search.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\TextData\\\\Trim\\:\\:\\$invalidChars has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Trim.php + + - + message: "#^Parameter \\#1 \\$str of function trim expects string, float\\|int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/TextData/Trim.php + + - + message: "#^Parameter \\#1 \\$str of function trim expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/TextData/Trim.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has parameter \\$onlyIf with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has parameter \\$onlyIfNot with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has parameter \\$reference with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has parameter \\$storeKey with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has parameter \\$type with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Token\\\\Stack\\:\\:getStackItem\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Calculation/Token/Stack.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\AdvancedValueBinder\\:\\:setImproperFraction\\(\\) has parameter \\$matches with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/AdvancedValueBinder.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\AdvancedValueBinder\\:\\:setProperFraction\\(\\) has parameter \\$matches with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/AdvancedValueBinder.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:\\$formulaAttributes has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Cell.php + + - + message: "#^Elseif branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Cell.php + + - + message: "#^Parameter \\#2 \\$format of static method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:toFormattedString\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Cell.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Cell.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:getFormulaAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Cell.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:splitRange\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Parameter \\#2 \\$str of function explode expects string, array\\\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:buildRange\\(\\) has parameter \\$pRange with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:rangeBoundaries\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:rangeDimension\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:getRangeBoundaries\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:extractAllCellReferencesInRange\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:processRangeSetOperators\\(\\) has parameter \\$cells with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:processRangeSetOperators\\(\\) has parameter \\$operators with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:processRangeSetOperators\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:sortCellReferenceArray\\(\\) has parameter \\$cellList with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:sortCellReferenceArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:getReferencesForCellBlock\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Parameter \\#4 \\$currentRow of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:validateRange\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Parameter \\#5 \\$endRow of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:validateRange\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:mergeRangesInCollection\\(\\) has parameter \\$pCoordCollection with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:mergeRangesInCollection\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Call to an undefined method object\\:\\:getHashCode\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Parameter \\#1 \\$input of function array_chunk expects array, array\\\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/Coordinate.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataType\\:\\:\\$errorCodes type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/DataType.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataType\\:\\:getErrorCodes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/DataType.php + + - + message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:substring\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Cell/DataType.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:getLineStyleProperty\\(\\) has parameter \\$elements with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Parameter \\#2 \\$alpha of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowColor\\(\\) expects int, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Parameter \\#1 \\$blur of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowBlur\\(\\) expects float, float\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Parameter \\#1 \\$angle of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowAngle\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Parameter \\#1 \\$distance of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowDistance\\(\\) expects float, float\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowProperiesMapValues\\(\\) has parameter \\$properties_map with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:getShadowProperty\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:getGlowProperty\\(\\) has parameter \\$property with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Axis.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$title \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$legend \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$xAxisLabel \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$yAxisLabel \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$plotArea \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$xAxis \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$yAxis \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$majorGridlines \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$minorGridlines \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftXOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftXOffset\\(\\) has parameter \\$xOffset with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getTopLeftXOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftYOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setTopLeftYOffset\\(\\) has parameter \\$yOffset with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getTopLeftYOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightPosition\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has parameter \\$cell with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightXOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightXOffset\\(\\) has parameter \\$xOffset with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightXOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightYOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightYOffset\\(\\) has parameter \\$yOffset with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightYOffset\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Chart.php + + - + message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues and null will always evaluate to false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Chart/DataSeries.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:\\$dataTypeValues has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/DataSeriesValues.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:\\$dataSource \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/DataSeriesValues.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:\\$fillColor \\(array\\\\|string\\) does not accept array\\\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/DataSeriesValues.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:setDataValues\\(\\) has parameter \\$dataValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/DataSeriesValues.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:refresh\\(\\) has parameter \\$flatten with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/DataSeriesValues.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:\\$objectState has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:\\$lineProperties has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:\\$shadowProperties has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:\\$glowProperties has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:\\$softEdges has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:getLineStyleProperty\\(\\) has parameter \\$elements with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Parameter \\#1 \\$color of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Parameter \\#2 \\$alpha of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Parameter \\#3 \\$type of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Parameter \\#1 \\$blur of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowBlur\\(\\) expects float, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Parameter \\#1 \\$angle of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowAngle\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Parameter \\#1 \\$distance of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowDistance\\(\\) expects float, float\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowProperiesMapValues\\(\\) has parameter \\$properties_map with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/GridLines.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\:\\:__construct\\(\\) has parameter \\$layout with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Layout.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:\\$positionXLref has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Legend.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Legend.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/PlotArea.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getTrueAlpha\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getTrueAlpha\\(\\) has parameter \\$alpha with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has parameter \\$alpha with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has parameter \\$color with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:setColorProperties\\(\\) has parameter \\$type with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getLineStyleArrowSize\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getLineStyleArrowSize\\(\\) has parameter \\$array_kay_selector with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getLineStyleArrowSize\\(\\) has parameter \\$array_selector with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getShadowPresetsMap\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getShadowPresetsMap\\(\\) has parameter \\$shadow_presets_option with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getArrayElementsValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getArrayElementsValue\\(\\) has parameter \\$elements with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getArrayElementsValue\\(\\) has parameter \\$properties with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Properties.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$width has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$height has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$colourSet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$markSet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$chart has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$graph has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$plotColour has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:\\$plotMark has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatPointMarker\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatPointMarker\\(\\) has parameter \\$markerID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatPointMarker\\(\\) has parameter \\$seriesPlot with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has parameter \\$datasetLabels with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has parameter \\$labelCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:formatDataSetLabels\\(\\) has parameter \\$rotation with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:percentageSumCalculation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:percentageSumCalculation\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:percentageSumCalculation\\(\\) has parameter \\$seriesCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:percentageAdjustValues\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:percentageAdjustValues\\(\\) has parameter \\$dataValues with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:percentageAdjustValues\\(\\) has parameter \\$sumValues with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:getCaption\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:getCaption\\(\\) has parameter \\$captionElement with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderCartesianPlotArea\\(\\) has parameter \\$type with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotLine\\(\\) has parameter \\$combination with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotLine\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotLine\\(\\) has parameter \\$filled with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotLine\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotBar\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotBar\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotScatter\\(\\) has parameter \\$bubble with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotScatter\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotRadar\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotContour\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPlotStock\\(\\) has parameter \\$groupID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderAreaChart\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderAreaChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderLineChart\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderLineChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderBarChart\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderBarChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderScatterChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderBubbleChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPieChart\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPieChart\\(\\) has parameter \\$doughnut with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPieChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderPieChart\\(\\) has parameter \\$multiplePlots with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderRadarChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderStockChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderContourChart\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderContourChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderCombinationChart\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderCombinationChart\\(\\) has parameter \\$dimensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderCombinationChart\\(\\) has parameter \\$groupCount with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Renderer\\\\JpGraph\\:\\:renderCombinationChart\\(\\) has parameter \\$outputDestination with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Renderer/JpGraph.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Chart/Title.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getParent\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet but returns PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getHighestRowAndColumn\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getCurrentCoordinate\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Parameter \\#1 \\$str of function sscanf expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Parameter \\#1 \\$columnIndex of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:stringFromColumnIndex\\(\\) expects int, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Possibly invalid array key type \\(array\\|string\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Cannot call method detach\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Cells.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:\\$cache has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Memory.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:deleteMultiple\\(\\) has parameter \\$keys with no value type specified in iterable type iterable\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Memory.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:getMultiple\\(\\) has parameter \\$keys with no value type specified in iterable type iterable\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Memory.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:getMultiple\\(\\) return type has no value type specified in iterable type iterable\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Memory.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:setMultiple\\(\\) has parameter \\$values with no value type specified in iterable type iterable\\.$#" + count: 1 + path: src/PhpSpreadsheet/Collection/Memory.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: "#^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: "#^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\\\\Document\\\\Properties\\:\\:\\$created \\(int\\) does not accept int\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Document/Properties.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:\\$modified \\(int\\) does not accept int\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Document/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:identifyPropertyType\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Document/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:identifyPropertyType\\(\\) has parameter \\$propertyValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Document/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:convertProperty\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Document/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:convertProperty\\(\\) has parameter \\$propertyValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Document/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:getCategories\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/DocumentGenerator.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:tableRow\\(\\) has parameter \\$lengths with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/DocumentGenerator.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:tableRow\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/DocumentGenerator.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:getPhpSpreadsheetFunctionText\\(\\) has parameter \\$functionCall with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/DocumentGenerator.php + + - + message: "#^Cannot access offset 0 on \\(int\\|string\\)\\.$#" + count: 2 + path: src/PhpSpreadsheet/DocumentGenerator.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\HashTable\\:\\:getIndexForHashCode\\(\\) should return int but returns int\\|string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/HashTable.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$colourMap has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$face has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$size has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$color has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$bold has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$italic has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$underline has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$superscript has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$subscript has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$strikethrough has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$startTagCallbacks has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$endTagCallbacks has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$stack has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:\\$stringData has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Parameter \\#1 \\$text of method PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\ITextElement\\:\\:setText\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setName\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setItalic\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setUnderline\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setSuperscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setSubscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Cannot call method setStrikethrough\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:rgbToColour\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:rgbToColour\\(\\) has parameter \\$rgb with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:startFontTag\\(\\) has parameter \\$tag with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:handleCallback\\(\\) has parameter \\$callbacks with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Parameter \\#1 \\$function of function call_user_func expects callable\\(\\)\\: mixed, array\\(\\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\), mixed\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Html.php + + - + message: "#^Parameter \\#1 \\$directory of class RecursiveDirectoryIterator constructor expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Parameter \\#1 \\$path of function pathinfo expects string, array\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Sample\\:\\:getSamples\\(\\) should return array\\\\> but returns array\\\\>\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Sample\\:\\:log\\(\\) has parameter \\$message with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Helper/Sample.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\IOFactory\\:\\:\\$readers has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/IOFactory.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\IOFactory\\:\\:\\$writers has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/IOFactory.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\NamedRange\\:\\:getCellsInRange\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/NamedRange.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\BaseReader\\:\\:\\$fileHandle has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/BaseReader.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\BaseReader\\:\\:getSecurityScanner\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/BaseReader.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:\\$delimiter \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, array\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:openFileOrMemory\\(\\) has parameter \\$pFilename with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:convertEncoding\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Parameter \\#1 \\$fp of function fwrite expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Argument of an invalid type array\\|null supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Parameter \\#2 \\$newvalue of function ini_set expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$fileHandle has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$escapeCharacter has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$enclosure has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$counts has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$numberLines has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:\\$delimiter has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$enclosure with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$escapeCharacter with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:__construct\\(\\) has parameter \\$fileHandle with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:countDelimiterValues\\(\\) has parameter \\$delimiterKeys with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:getNextLine\\(\\) should return string\\|false but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:\\$expressions type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:\\$referenceHelper has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Parameter \\#1 \\$fp of function fread expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Parameter \\#1 \\$fp of function fclose expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:\\$mappings has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:gnumericMappings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCreated\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setModified\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:docPropertiesMeta\\(\\) has parameter \\$namespacesMeta with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:docProperties\\(\\) has parameter \\$namespacesMeta with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addBorderDiagonal\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addBorderStyle\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Offset 'No' does not exist on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Offset 'Unit' does not exist on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Offset 'DefaultSizePts' does not exist on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addStyle\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addStyle2\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseBorderAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseBorderAttributes\\(\\) has parameter \\$borderAttributes with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseRichText\\(\\) has parameter \\$is with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseGnumericColour\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseGnumericColour\\(\\) has parameter \\$gnmColour with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addColors\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\\\PageSetup\\:\\:buildMarginSet\\(\\) has parameter \\$marginSet with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\\\PageSetup\\:\\:buildMarginSet\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\\\PageSetup\\:\\:adjustMargins\\(\\) has parameter \\$marginSet with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$formats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$rowspan has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:readBeginning\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:readEnding\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Parameter \\#2 \\$length of function fread expects int, int\\\\|int\\<1, 2048\\>\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:startsWithTag\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:startsWithTag\\(\\) has parameter \\$data with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:endsWithTag\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:endsWithTag\\(\\) has parameter \\$data with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:containsTags\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:containsTags\\(\\) has parameter \\$data with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$dataArray has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$tableLevel has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$nestedColumn has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:setTableStartColumn\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:setTableStartColumn\\(\\) has parameter \\$column with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:getTableStartColumn\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:releaseTableStartColumn\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:flushCell\\(\\) has parameter \\$cellContent with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:flushCell\\(\\) has parameter \\$column with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:flushCell\\(\\) has parameter \\$row with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Argument of an invalid type DOMNamedNodeMap\\|null supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementTitle\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$spanEtc has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementSpanEtc\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementHr\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementBr\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementA\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$h1Etc has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementH1Etc\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementLi\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementImg\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementTable\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementTr\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementThTdOther\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementBgcolor\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementWidth\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementHeight\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementAlign\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementVAlign\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementDataFormat\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementThTd\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:applyInlineStyle\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Parameter \\#2 \\$styleValue of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:setBorderStyle\\(\\) expects string, string\\|null given\\.$#" + count: 5 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:setHorizontal\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:setVertical\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:getStyleColor\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:insertImage\\(\\) has parameter \\$attributes with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$borderMappings has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:getBorderMappings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Html.php + + - + message: "#^Cannot call method getNamespaces\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method children\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:listWorksheetNames\\(\\) should return array\\ but returns array\\\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method getElementsByTagNameNS\\(\\) on DOMElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Parameter \\#1 \\$element of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:scanElementForText\\(\\) expects DOMNode, DOMElement\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method getAttributeNS\\(\\) on DOMElement\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Parameter \\#1 \\$settings of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:lookForActiveSheet\\(\\) expects DOMElement, DOMElement\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Parameter \\#1 \\$settings of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:lookForSelectedCells\\(\\) expects DOMElement, DOMElement\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method setSelectedCellByColumnAndRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Cannot call method getNamedItem\\(\\) on DOMNamedNodeMap\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^If condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 7 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:convertToExcelAddressValue\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Parameter \\#3 \\$formula of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:translateSeparator\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$officeNs has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$stylesNs has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$stylesFo has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$pageLayoutStyles has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$masterStylesCrossReference has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\PageSettings\\:\\:\\$masterPrintStylesCrossReference has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Cannot call method getElementsByTagNameNS\\(\\) on DOMElement\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Ods/PageSettings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:load\\(\\) has parameter \\$namespacesMeta with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCreated\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setModified\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:setMetaProperties\\(\\) has parameter \\$namespacesMeta with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:setMetaProperties\\(\\) has parameter \\$propertyName with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:setUserDefinedProperty\\(\\) has parameter \\$propertyValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\\\Properties\\:\\:setUserDefinedProperty\\(\\) has parameter \\$propertyValueAttributes with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Ods/Properties.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:\\$callback has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:\\$libxmlDisableEntityLoaderValue has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:__construct\\(\\) has parameter \\$pattern with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:getInstance\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:threadSafeLibxmlDisableEntityLoaderAvailability\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:toUtf8\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Security\\\\XmlScanner\\:\\:toUtf8\\(\\) has parameter \\$xml with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, array\\\\|string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$formats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$fonts type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Parameter \\#1 \\$haystack of function substr_count expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Parameter \\#2 \\$str of function explode expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$colorArray has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$fontStyleMappings has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processCRecord\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processFRecord\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$styleSettingsFont has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$styleSettingsBorder has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:styleSettings\\(\\) has parameter \\$styleData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:addStyle\\(\\) has parameter \\$styleData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Parameter \\#1 \\$columnIndex of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:stringFromColumnIndex\\(\\) expects int, string given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPRecord\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPColors\\(\\) has parameter \\$formatArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPFontStyles\\(\\) has parameter \\$formatArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPFinal\\(\\) has parameter \\$formatArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:columnRowFromRowData\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Slk.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$formats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$palette type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sheets type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$externalBooks type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$ref type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$externalNames type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$definedname type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sst type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$objs type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$textObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$cellNotes type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$mapCellXfIndex type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$mapCellStyleXfIndex type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sharedFormulas type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sharedFormulaParts type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:getDgContainer\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getNestingLevel\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getStartCoordinates\\(\\)\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getEndCoordinates\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getStartOffsetX\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getStartOffsetY\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getEndOffsetX\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getEndOffsetY\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#2 \\$startRow of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Xls\\:\\:getDistanceY\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#4 \\$endRow of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Xls\\:\\:getDistanceY\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#2 \\$row of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Xls\\:\\:sizeRow\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method object\\:\\:getOPT\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:getDggContainer\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^If condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\MemoryDrawing\\:\\:setImageResource\\(\\) expects GdImage\\|resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\BaseDrawing\\:\\:setOffsetX\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\BaseDrawing\\:\\:setOffsetY\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#2 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReadFilter\\:\\:readCell\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 12 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$block of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:makeKey\\(\\) expects int, float given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$data \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$summaryInformation \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$documentSummaryInformation \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$codePage of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\CodePage\\:\\:numberToName\\(\\) expects int, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$title of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setTitle\\(\\) expects string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$subject of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setSubject\\(\\) expects string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$creator of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCreator\\(\\) expects string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$keywords of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setKeywords\\(\\) expects string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$description of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setDescription\\(\\) expects string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$modifier of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setLastModifiedBy\\(\\) expects string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$codePage of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\CodePage\\:\\:numberToName\\(\\) expects int, bool\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$category of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCategory\\(\\) expects string, bool\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$manager of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setManager\\(\\) expects string, bool\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$company of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCompany\\(\\) expects string, bool\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#2 \\$pos of static method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:getUInt2d\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#2 \\$pos of static method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:getInt4d\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#2 \\$start of function substr expects int, float\\|int given\\.$#" + count: 5 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:setShowSummaryBelow\\(\\) expects bool, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:setShowSummaryRight\\(\\) expects bool, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setOutlineLevel\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setCollapsed\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setOutlineLevel\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setCollapsed\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 9 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:includeCellRangeFiltered\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:includeCellRangeFiltered\\(\\) has parameter \\$cellRangeAddress with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method getHyperLink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot call method getDataValidation\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setType\\(\\) expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setErrorStyle\\(\\) expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setOperator\\(\\) expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 8 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:getSplicedRecordData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:createFormulaFromTokens\\(\\) has parameter \\$tokens with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:getNextToken\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF8CellRangeAddressList\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF5CellRangeAddressList\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF8ConstantArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF8Constant\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readRGB\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readByteStringShort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readByteStringLong\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readUnicodeStringShort\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readUnicodeStringLong\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readUnicodeString\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Cannot access offset 1 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:parseRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:parseRichText\\(\\) has parameter \\$is with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\:\\:map\\(\\) has parameter \\$palette with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\:\\:map\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF5\\:\\:\\$map has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF5\\:\\:lookup\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF8\\:\\:\\$map has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF8\\:\\:lookup\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BuiltIn\\:\\:\\$map has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BuiltIn\\:\\:lookup\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\ErrorCode\\:\\:\\$map has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/ErrorCode.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setDggContainer\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setBstoreContainer\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:addBSE\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setBlip\\(\\)\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setDgContainer\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:addChild\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:addChild\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setStartCoordinates\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setStartOffsetX\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setStartOffsetY\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setEndCoordinates\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setEndOffsetX\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setEndOffsetY\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setOPT\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Escher.php + + - + message: "#^Parameter \\#1 \\$input of function array_values expects array, array\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\MD5\\:\\:f\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\MD5\\:\\:g\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\MD5\\:\\:h\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\MD5\\:\\:i\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\MD5\\:\\:step\\(\\) has parameter \\$func with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\MD5\\:\\:rotate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/MD5.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\RC4\\:\\:\\$s has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/RC4.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\RC4\\:\\:\\$i has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/RC4.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\RC4\\:\\:\\$j has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/RC4.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Style\\\\Border\\:\\:\\$map has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Style/Border.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Style\\\\FillPattern\\:\\:\\$map has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xls/Style/FillPattern.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$Relationship on SimpleXMLElement\\|false\\.$#" + count: 12 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$sheets on SimpleXMLElement\\|false\\.$#" + count: 6 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method registerXPathNamespace\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 4 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToBoolean\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToBoolean\\(\\) has parameter \\$c with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToError\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToError\\(\\) has parameter \\$c with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToString\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToString\\(\\) has parameter \\$c with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$c with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$calculatedValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$castBaseType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$cellDataType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$r with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$sharedFormulas with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:castToFormula\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:getFromZipArchive\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Offset 'name' does not exist on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method xpath\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 4 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$is of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:parseRichText\\(\\) expects SimpleXMLElement\\|null, object given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$styleXml of class PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles constructor expects SimpleXMLElement, SimpleXMLElement\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$workbookPr on SimpleXMLElement\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#2 \\$xmlWorkbook of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readProtection\\(\\) expects SimpleXMLElement, SimpleXMLElement\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setFormulaAttributes\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$relsWorksheet of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Hyperlinks\\:\\:readHyperlinks\\(\\) expects SimpleXMLElement, SimpleXMLElement\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$authors on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$commentList on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Negated boolean expression is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$drawing on SimpleXMLElement\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method children\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method count\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method asXML\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$definedNames on SimpleXMLElement\\|false\\.$#" + count: 4 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$pName of method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getSheetByName\\(\\) expects string, array\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access offset 0 on array\\\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$bookViews on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$Default on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$Override on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$chartElements of static method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readChart\\(\\) expects SimpleXMLElement, SimpleXMLElement\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method addChart\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readColor\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readColor\\(\\) has parameter \\$background with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readColor\\(\\) has parameter \\$color with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$hex of static method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:changeBrightness\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:setSize\\(\\) expects float, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot access property \\$r on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setName\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setItalic\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setSuperscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setSubscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setUnderline\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Cannot call method setStrikethrough\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:getArrayItem\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:getArrayItem\\(\\) has parameter \\$array with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:getArrayItem\\(\\) has parameter \\$key with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:dirAdd\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:dirAdd\\(\\) has parameter \\$add with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:dirAdd\\(\\) has parameter \\$base with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:toCSSArray\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:toCSSArray\\(\\) has parameter \\$style with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$fontSizeInPoints of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:fontSizeToPixels\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$sizeInInch of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:inchSizeToPixels\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Parameter \\#1 \\$sizeInCm of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:centimeterSizeToPixels\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:stripWhiteSpaceFromStyleString\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:stripWhiteSpaceFromStyleString\\(\\) has parameter \\$string with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:boolean\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:boolean\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readHyperLinkDrawing\\(\\) has parameter \\$hyperlinks with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Offset 'id' does not exist on SimpleXMLElement\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readFormControlProperties\\(\\) has parameter \\$dir with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readFormControlProperties\\(\\) has parameter \\$docSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readFormControlProperties\\(\\) has parameter \\$fileWorksheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readFormControlProperties\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readPrinterSettings\\(\\) has parameter \\$dir with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readPrinterSettings\\(\\) has parameter \\$docSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readPrinterSettings\\(\\) has parameter \\$fileWorksheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readPrinterSettings\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\AutoFilter\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\AutoFilter\\:\\:\\$worksheetXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\AutoFilter\\:\\:readAutoFilter\\(\\) has parameter \\$autoFilterRange with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\AutoFilter\\:\\:readAutoFilter\\(\\) has parameter \\$xmlSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php + + - + message: "#^Parameter \\#1 \\$pOperator of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:setRule\\(\\) expects string, null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\BaseParserClass\\:\\:boolean\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/BaseParserClass.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\BaseParserClass\\:\\:boolean\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/BaseParserClass.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readColor\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readColor\\(\\) has parameter \\$background with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readColor\\(\\) has parameter \\$color with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Parameter \\#1 \\$position of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend constructor expects string, bool\\|float\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Parameter \\#3 \\$overlay of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend constructor expects bool, bool\\|float\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Parameter \\#6 \\$displayBlanksAs of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart constructor expects string, bool\\|float\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartTitle\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartTitle\\(\\) has parameter \\$namespacesChartMeta with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has parameter \\$chartDetail with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has parameter \\$namespacesChartMeta with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has parameter \\$chartDetail with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has parameter \\$namespacesChartMeta with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeries\\(\\) has parameter \\$plotType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Parameter \\#3 \\$plotOrder of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeries constructor expects array\\, array\\ given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Parameter \\#7 \\$plotDirection of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeries constructor expects string\\|null, bool\\|float\\|int\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has parameter \\$marker with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has parameter \\$namespacesChartMeta with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValueSet\\(\\) has parameter \\$seriesDetail with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Parameter \\#4 \\$pointCount of class PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues constructor expects int, null given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValues\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValues\\(\\) has parameter \\$dataType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValues\\(\\) has parameter \\$seriesValueSet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValuesMultiLevel\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValuesMultiLevel\\(\\) has parameter \\$dataType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartDataSeriesValuesMultiLevel\\(\\) has parameter \\$seriesValueSet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:parseRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method getFont\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\Run\\|null\\.$#" + count: 12 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setName\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setItalic\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setSuperscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setSubscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setUnderline\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Cannot call method setStrikethrough\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readChartAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:readChartAttributes\\(\\) has parameter \\$chartDetail with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:\\$worksheetXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:setColumnAttributes\\(\\) has parameter \\$columnAttributes with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:setRowAttributes\\(\\) has parameter \\$rowAttributes with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredColumn\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredColumn\\(\\) has parameter \\$columnCoordinate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredColumn\\(\\) has parameter \\$rowsAttributes with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readColumnAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readColumnAttributes\\(\\) has parameter \\$readDataOnly with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readColumnRangeAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readColumnRangeAttributes\\(\\) has parameter \\$readDataOnly with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredRow\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredRow\\(\\) has parameter \\$columnsAttributes with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredRow\\(\\) has parameter \\$rowCoordinate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readRowAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readRowAttributes\\(\\) has parameter \\$readDataOnly with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:\\$worksheetXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:\\$dxfs has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:__construct\\(\\) has parameter \\$dxfs with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readConditionalStyles\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readConditionalStyles\\(\\) has parameter \\$xmlSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:setConditionalStyles\\(\\) has parameter \\$conditionals with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:setConditionalStyles\\(\\) has parameter \\$xmlExtLst with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readStyleRules\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readStyleRules\\(\\) has parameter \\$cfRules with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readStyleRules\\(\\) has parameter \\$extLst with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readDataBarOfConditionalRule\\(\\) has parameter \\$cfRule with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readDataBarOfConditionalRule\\(\\) has parameter \\$conditionalFormattingRuleExtensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readDataBarExtLstOfConditionalRule\\(\\) has parameter \\$cfRule with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readDataBarExtLstOfConditionalRule\\(\\) has parameter \\$conditionalFormattingRuleExtensions with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\DataValidations\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\DataValidations\\:\\:\\$worksheetXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/DataValidations.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Hyperlinks\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Hyperlinks\\:\\:\\$hyperlinks has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:\\$worksheetXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:load\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:load\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:pageSetup\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:pageSetup\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:\\$securityScanner has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:\\$docProps has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:extractPropertyData\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:extractPropertyData\\(\\) has parameter \\$propertyData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:readCoreProperties\\(\\) has parameter \\$propertyData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Call to an undefined method object\\:\\:registerXPathNamespace\\(\\)\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Call to an undefined method object\\:\\:xpath\\(\\)\\.$#" + count: 9 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:readExtendedProperties\\(\\) has parameter \\$propertyData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:readCustomProperties\\(\\) has parameter \\$propertyData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Argument of an invalid type object supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:getArrayItem\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:getArrayItem\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:getArrayItem\\(\\) has parameter \\$key with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\SheetViewOptions\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/SheetViewOptions.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\SheetViewOptions\\:\\:\\$worksheetXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/SheetViewOptions.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\SheetViews\\:\\:\\$sheetViewXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/SheetViews.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\SheetViews\\:\\:\\$worksheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/SheetViews.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:\\$styles has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:\\$cellStyles has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:\\$styleXml has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:setStyleBaseData\\(\\) has parameter \\$cellStyles with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:setStyleBaseData\\(\\) has parameter \\$styles with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Static property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:\\$theme \\(PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Theme\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Theme\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Cannot call method count\\(\\) on SimpleXMLElement\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readStyle\\(\\) has parameter \\$style with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Parameter \\#2 \\$alignmentXml of static method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readAlignmentStyle\\(\\) expects SimpleXMLElement, object given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readProtectionLocked\\(\\) has parameter \\$style with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readProtectionHidden\\(\\) has parameter \\$style with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readColor\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readColor\\(\\) has parameter \\$background with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:readColor\\(\\) has parameter \\$color with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Parameter \\#1 \\$hex of static method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:changeBrightness\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:dxfs\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:dxfs\\(\\) has parameter \\$readDataOnly with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:styles\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:getArrayItem\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:getArrayItem\\(\\) has parameter \\$array with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Styles\\:\\:getArrayItem\\(\\) has parameter \\$key with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$styles type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$fileContents has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$mappings has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:xmlMappings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:convertEncoding\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method getNamespaces\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method children\\(\\) on SimpleXMLElement\\|false\\.$#" + count: 3 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:identifyFixedStyleValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:identifyFixedStyleValue\\(\\) has parameter \\$styleAttributeValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:identifyFixedStyleValue\\(\\) has parameter \\$styleList with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:hex2str\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:hex2str\\(\\) has parameter \\$hex with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot access property \\$DocumentProperties on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCreated\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setModified\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#2 \\$callback of function preg_replace_callback expects callable\\(\\)\\: mixed, array\\('self', 'hex2str'\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Parameter \\#1 \\$xml of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyles\\(\\) expects SimpleXMLElement, SimpleXMLElement\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Cannot access property \\$Names on SimpleXMLElement\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseRichText\\(\\) has parameter \\$is with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyles\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$borderPositions has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyleBorders\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyleBorders\\(\\) has parameter \\$styleID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$underlineStyles has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyleInterior\\(\\) has parameter \\$styleID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyleNumberFormat\\(\\) has parameter \\$styleID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\\\PageSettings\\:\\:__construct\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml/PageSettings.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\\\PageSettings\\:\\:pageSetup\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Reader/Xml/PageSettings.php + + - + message: "#^Parameter \\#2 \\$cmp_function of function uksort expects callable\\(mixed, mixed\\)\\: int, array\\('self', 'cellReverseSort'\\) given\\.$#" + count: 4 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Parameter \\#2 \\$cmp_function of function uksort expects callable\\(mixed, mixed\\)\\: int, array\\('self', 'cellSort'\\) given\\.$#" + count: 4 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Parameter \\#2 \\$pPassword of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:protectCells\\(\\) expects string, array given\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\:\\:setRowIndex\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getOutlineLevel\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setOutlineLevel\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getCollapsed\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setCollapsed\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getColumn\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Parameter \\#1 \\$columnIndex of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:stringFromColumnIndex\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Parameter \\#1 \\$pCellRange of method PhpOffice\\\\PhpSpreadsheet\\\\ReferenceHelper\\:\\:updateCellReference\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/ReferenceHelper.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\Run\\:\\:\\$font \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/RichText/Run.php + + - + message: "#^Result of && is always false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Settings.php + + - + message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Settings.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Settings.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:getHttpClient\\(\\) should return Psr\\\\Http\\\\Client\\\\ClientInterface but returns Psr\\\\Http\\\\Client\\\\ClientInterface\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Settings.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:getRequestFactory\\(\\) should return Psr\\\\Http\\\\Message\\\\RequestFactoryInterface but returns Psr\\\\Http\\\\Message\\\\RequestFactoryInterface\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Settings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\CodePage\\:\\:\\$pageArray has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/CodePage.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\CodePage\\:\\:getEncodings\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/CodePage.php + + - + message: "#^Parameter \\#1 \\$dateValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:timestampToExcel\\(\\) expects int, float\\|int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Date.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Shared/Date.php + + - + message: "#^Parameter \\#1 \\$pFormatCode of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:isDateTimeFormatCode\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Date.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:\\$possibleDateFormatCharacters has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Date.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) should return int but returns float\\|int\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#1 \\$fp of function fread expects resource, resource\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#1 \\$fp of function feof expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#2 \\$data of function unpack expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Cannot access offset 1 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#1 \\$x_size of function imagecreatetruecolor expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#2 \\$y_size of function imagecreatetruecolor expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#1 \\$im of function imagecolorallocate expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#2 \\$red of function imagecolorallocate expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#3 \\$green of function imagecolorallocate expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#4 \\$blue of function imagecolorallocate expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#1 \\$im of function imagesetpixel expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#3 \\$y of function imagesetpixel expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Parameter \\#4 \\$col of function imagesetpixel expects int, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:imagecreatefrombmp\\(\\) should return GdImage\\|resource but returns resource\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Drawing.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:\\$spgrContainer has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:getDgId\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:setDgId\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:getLastSpId\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:setLastSpId\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:getSpgrContainer\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:setSpgrContainer\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\:\\:setSpgrContainer\\(\\) has parameter \\$spgrContainer with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\:\\:\\$children type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\:\\:getChildren\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\:\\:\\$OPT type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\:\\:getOPTCollection\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:\\$OPT type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:\\$IDCLs type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:getIDCLs\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:setIDCLs\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\:\\:\\$BSECollection type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer.php + + - + message: "#^Strict comparison using \\=\\=\\= between string\\|false and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/File.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\File\\:\\:realpath\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/File.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\File\\:\\:sysGetTempDir\\(\\) should return string but returns string\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Shared/File.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:\\$autoSizeMethods has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:\\$defaultColumnWidths type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Parameter \\#2 \\$pDefaultFont of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Parameter \\#1 \\$size of function imagettfbbox expects float, float\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Cannot access offset 0 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Cannot access offset 2 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Cannot access offset 4 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Cannot access offset 6 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Font.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\CholeskyDecomposition\\:\\:\\$L type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/CholeskyDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$d type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$e has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$V type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$H type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$ort type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$cdivi has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$A type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:getRealEigenvalues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:getImagEigenvalues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:\\$LU type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:\\$piv type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php + + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:getPivot\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:getDoublePivot\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:\\$A type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:__construct\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 19 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:getArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:getMatrix\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:plus\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:plusEquals\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Call to function is_string\\(\\) with float\\|int will always evaluate to false\\.$#" + count: 5 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Result of && is always false\\.$#" + count: 10 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:minus\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:minusEquals\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayTimes\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayTimesEquals\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayRightDivide\\(\\) has parameter \\$args with no typehint 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: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayRightDivideEquals\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayLeftDivide\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:arrayLeftDivideEquals\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:times\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:power\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:concat\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Parameter \\#1 \\$str of function trim expects string, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\QRDecomposition\\:\\:\\$QR type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\QRDecomposition\\:\\:\\$Rdiag type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:\\$U type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:\\$V type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:\\$s type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php + + - + message: "#^Left side of && is always true\\.$#" + count: 4 + path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php + + - + message: "#^If condition is always true\\.$#" + count: 7 + path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:getSingularValues\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:\\$_list type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:\\$bbat type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:\\$sbat type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:getStream\\(\\) should return resource but returns resource\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#2 \\$data of function unpack expects string, string\\|false given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#1 \\$time_1st of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#2 \\$time_2nd of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#1 \\$No of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#2 \\$name of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects string, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#3 \\$type of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#4 \\$prev of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#5 \\$next of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#6 \\$dir of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#7 \\$time_1st of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#8 \\$time_2nd of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#9 \\$data of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS constructor expects string, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Parameter \\#1 \\$oleTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:OLE2LocalDate\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:getData\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Cannot access offset 3 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Cannot access offset 4 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Cannot access offset 1 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Cannot access offset 2 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\ChainedBlockStream\\:\\:\\$params type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php + + - + message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\ChainedBlockStream\\:\\:stream_stat\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:\\$children type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) has parameter \\$children with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:savePpsSetPnt\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS.php + + - + message: "#^Parameter \\#3 \\$length of function array_slice expects int\\|null, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS.php + + - + message: "#^Parameter \\#2 \\$offset of function array_slice expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS.php + + - + message: "#^Parameter \\#1 \\$No of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/File.php + + - + message: "#^Parameter \\#4 \\$prev of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/File.php + + - + message: "#^Parameter \\#5 \\$next of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/File.php + + - + message: "#^Parameter \\#6 \\$dir of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/File.php + + - + message: "#^Parameter \\#7 \\$time_1st of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/File.php + + - + message: "#^Parameter \\#8 \\$time_2nd of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/File.php + + - + message: "#^Parameter \\#1 \\$No of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#4 \\$prev of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#5 \\$next of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#6 \\$dir of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#9 \\$data of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) expects string, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#1 \\$iSBDcnt of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveHeader\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#2 \\$iBBcnt of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveHeader\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#3 \\$iPPScnt of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveHeader\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#1 \\$iStBlk of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveBigData\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#1 \\$iSbdSize of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveBbd\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#2 \\$iBsize of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveBbd\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Parameter \\#3 \\$iPpsCnt of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveBbd\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:calcSize\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveBigData\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:makeSmallData\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:savePps\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$data has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$wrkbook has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$summaryInformation has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$documentSummaryInformation has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$props type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Parameter \\#1 \\$data of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:getInt4d\\(\\) expects string, string\\|false given\\.$#" + count: 8 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/OLERead.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/PasswordHasher.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:\\$SYLKCharacters type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:sanitizeUTF8\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:formatNumber\\(\\) should return string but returns array\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:countCharacters\\(\\) should return int but returns int\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbIsUpper\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbIsUpper\\(\\) has parameter \\$char with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbStrSplit\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:mbStrSplit\\(\\) has parameter \\$string with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/StringHelper.php + + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/TimeZone.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$goodnessOfFit has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$stdevOfResiduals has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$covariance has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$correlation has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$SSRegression has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$SSResiduals has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$DFResiduals has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$f has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$slope has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$slopeSE has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$intersect has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$intersectSE has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$xOffset has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:\\$yOffset has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:getError\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:getBestFitType\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$const with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$meanX with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$meanY with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$sumX with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$sumX2 with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$sumXY with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$sumY with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:calculateGoodnessOfFit\\(\\) has parameter \\$sumY2 with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:sumSquares\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:sumSquares\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/BestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\PolynomialBestFit\\:\\:getCoefficients\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\PolynomialBestFit\\:\\:getCoefficients\\(\\) has parameter \\$dp with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php + + - + message: "#^Parameter \\#2 \\.\\.\\.\\$args of function array_merge expects array, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/PolynomialBestFit.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\Trend\\:\\:calculate\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/Trend.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\Trend\\:\\:calculate\\(\\) has parameter \\$const with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/Trend.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\Trend\\:\\:calculate\\(\\) has parameter \\$trendType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/Trend.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\Trend\\:\\:calculate\\(\\) has parameter \\$xValues with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/Trend.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\Trend\\:\\:calculate\\(\\) has parameter \\$yValues with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Trend/Trend.php + + - + message: "#^Parameter \\#1 \\$order of class PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\PolynomialBestFit constructor expects int, string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Shared/Trend/Trend.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:\\$debugEnabled has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/XMLWriter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:\\$tempFileName \\(string\\) does not accept string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/XMLWriter.php + + - + message: "#^Parameter \\#1 \\$uri of method XMLWriter\\:\\:openUri\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/XMLWriter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:getData\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/XMLWriter.php + + - + message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pointsToPixels\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Xls.php + + - + message: "#^Parameter \\#1 \\$fontSizeInPoints of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:fontSizeToPixels\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Xls\\:\\:oneAnchor2twoAnchor\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Shared/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$workbookViewVisibilityValues has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$ribbonBinObjects type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$unparsedLoadedData type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getRibbonXMLData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getUnparsedLoadedData\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:setUnparsedLoadedData\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getRibbonBinObjects\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Parameter \\#1 \\$pSheet of method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getIndex\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet, PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Comparison operation \"\\<\\=\" between int\\ and 1000 is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Result of \\|\\| is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Spreadsheet.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Alignment.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Alignment.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Alignment.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Alignment.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Alignment.php + + - + message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Right side of && is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Border.php + + - + message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\) given\\.$#" + count: 10 + path: src/PhpSpreadsheet/Style/Borders.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Borders.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Borders.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Borders.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Borders.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Borders.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:\\$indexedColors type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getEndColor\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getStartColor\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getColor\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getColourComponent\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Color.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:\\$condition \\(array\\\\) does not accept array\\\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Conditional.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:\\$style \\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Conditional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\:\\:setShowValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\:\\:setMinimumConditionalFormatValueObject\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\:\\:setMaximumConditionalFormatValueObject\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\:\\:setConditionalFormattingRuleExt\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:\\$axisColor type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:getXmlAttributes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:getXmlElements\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:setMaximumConditionalFormatValueObject\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:setMinimumConditionalFormatValueObject\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:getAxisColor\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:\\$type has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:\\$value has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:\\$cellFormula has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:__construct\\(\\) has parameter \\$type with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:__construct\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:setType\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:setValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:setCellFormula\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormatValueObject.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormattingRuleExtension\\:\\:\\$id has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormattingRuleExtension\\:\\:__construct\\(\\) has parameter \\$id with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormattingRuleExtension\\:\\:generateUuid\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormattingRuleExtension\\:\\:parseExtLstXml\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormattingRuleExtension\\:\\:parseExtLstXml\\(\\) has parameter \\$extLstXml with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$minLength on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$maxLength on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$border on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$gradient on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$direction on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$negativeBarBorderColorSameAsPositive on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Cannot access property \\$axisPosition on SimpleXMLElement\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormattingRuleExtension\\:\\:parseExtDataBarElementChildrenFromXml\\(\\) has parameter \\$ns with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Offset 'rgb' does not exist on SimpleXMLElement\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Offset 'theme' does not exist on SimpleXMLElement\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Offset 'tint' does not exist on SimpleXMLElement\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalFormattingRuleExtension.php + + - + message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\) given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/Fill.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Fill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Fill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Fill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Fill.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Fill.php + + - + message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Font.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Font.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Font.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$builtInFormats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$flippedBuiltInFormats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$builtInFormatCode \\(int\\|false\\) does not accept bool\\|int\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:toFormattedString\\(\\) has parameter \\$callBack with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:\\$dateFormatReplacements type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:\\$dateFormatReplacements24 type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:\\$dateFormatReplacements12 type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:format\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#2 \\$callback of function preg_replace_callback expects callable\\(\\)\\: mixed, array\\('self', 'setLowercaseCallback'\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace_callback expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#2 \\$str of function explode expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#2 \\$replace of function str_replace expects array\\|string, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#2 \\$callback of function preg_replace_callback expects callable\\(\\)\\: mixed, array\\('self', 'escapeQuotesCallback'\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Parameter \\#1 \\$format of method DateTime\\:\\:format\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:setLowercaseCallback\\(\\) has parameter \\$matches with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:escapeQuotesCallback\\(\\) has parameter \\$matches with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormatCompare\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormatCompare\\(\\) has parameter \\$cond with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormatCompare\\(\\) has parameter \\$dfcond with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormatCompare\\(\\) has parameter \\$dfval with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormatCompare\\(\\) has parameter \\$val with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormatCompare\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormat\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormat\\(\\) has parameter \\$sections with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:splitFormat\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:toFormattedString\\(\\) has parameter \\$callBack with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:toFormattedString\\(\\) should return string but returns float\\|int\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_split expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\FractionFormatter\\:\\:format\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php + + - + message: "#^Parameter \\#1 \\$str of function trim expects string, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/FractionFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:mergeComplexNumberFormatMasks\\(\\) has parameter \\$masks with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:mergeComplexNumberFormatMasks\\(\\) has parameter \\$numbers with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:mergeComplexNumberFormatMasks\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:processComplexNumberFormatMask\\(\\) has parameter \\$mask with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:processComplexNumberFormatMask\\(\\) has parameter \\$number with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:complexNumberFormatMask\\(\\) has parameter \\$mask with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:complexNumberFormatMask\\(\\) has parameter \\$number with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:complexNumberFormatMask\\(\\) has parameter \\$splitOnPoint with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Parameter \\#2 \\$str of function explode expects string, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:formatStraightNumericValue\\(\\) has parameter \\$format with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:formatStraightNumericValue\\(\\) has parameter \\$matches with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:formatStraightNumericValue\\(\\) has parameter \\$useThousands with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:formatStraightNumericValue\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:format\\(\\) has parameter \\$format with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:format\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, array\\|string\\|null given\\.$#" + count: 6 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, array\\|string\\|null given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Parameter \\#2 \\$format of static method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\FractionFormatter\\:\\:format\\(\\) expects string, array\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\PercentageFormatter\\:\\:format\\(\\) has parameter \\$value with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php + + - + message: "#^Parameter \\#1 \\$format of function sprintf expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/NumberFormat/PercentageFormatter.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Protection.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Protection.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Protection.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Protection.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Protection.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getCellXfByIndex\\(\\)\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getParent\\(\\) should return PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet but returns PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) has parameter \\$rangeEnd with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) has parameter \\$rangeStart with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Style.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:exportArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Supervisor.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Supervisor.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:exportArray2\\(\\) has parameter \\$exportedArray with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Style/Supervisor.php + + - + message: "#^Result of && is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#1 \\$excelTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:excelToTimestamp\\(\\) expects float\\|int, float\\|int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\<1, max\\>\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:\\$fromReplace type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:\\$toReplace has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#2 \\$now of function strtotime expects int, int\\|false given\\.$#" + count: 6 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#5 \\$day of function gmmktime expects int, string given\\.$#" + count: 8 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#6 \\$year of function gmmktime expects int, string given\\.$#" + count: 13 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#4 \\$mon of function gmmktime expects int, string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#5 \\$day of function gmmktime expects int, float given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#1 \\$attributes of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttributes\\(\\) expects array\\, array\\ given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$columnID with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$endRow with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$ruleType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$ruleValue with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:calculateTopTenValue\\(\\) has parameter \\$startRow with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot call method rangeToArray\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot call method getRowDimension\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot assign offset 'year' to array\\\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot assign offset 'month' to array\\\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot assign offset 'day' to array\\\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot assign offset 'hour' to array\\\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot assign offset 'minute' to array\\\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot assign offset 'second' to array\\\\|string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#1 \\$str of function preg_quote expects string, array\\\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Binary operation \"\\*\" between 0\\|array\\\\|string and float\\|int results in an error\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Left side of && is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Parameter \\#1 \\$function of function call_user_func_array expects callable\\(\\)\\: mixed, array\\('PhpOffice\\\\\\\\PhpSpreadsheet\\\\\\\\Worksheet\\\\\\\\AutoFilter', mixed\\) given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$ruleTypes has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$dateTimeGroups has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$dynamicTypes has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$operators has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$topTenValue has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$topTenType has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/AutoFilter/Column/Rule.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php + + - + message: "#^Cannot call method getDrawingCollection\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\BaseDrawing\\:\\:\\$shadow \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Drawing\\\\Shadow\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php + + - + message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/BaseDrawing.php + + - + message: "#^Class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator implements generic interface Iterator but does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/CellIterator.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator\\:\\:adjustForExistingOnlyRange\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/CellIterator.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Column\\:\\:\\$parent \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Column.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/ColumnCellIterator.php + + - + message: "#^Class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnIterator implements generic interface Iterator but does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/ColumnIterator.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: "#^Class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Iterator implements generic interface Iterator but does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Iterator.php + + - + message: "#^Parameter \\#1 \\$im of function imagesx expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/MemoryDrawing.php + + - + message: "#^Parameter \\#1 \\$im of function imagesy expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/MemoryDrawing.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$columnsToRepeatAtLeft type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$rowsToRepeatAtTop type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$pageOrder has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Strict comparison using \\=\\=\\= between int\\ and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getColumnsToRepeatAtLeft\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:setColumnsToRepeatAtLeft\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getRowsToRepeatAtTop\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:setRowsToRepeatAtTop\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getPrintArea\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Parameter \\#2 \\$str of function explode expects string, string\\|null given\\.$#" + count: 5 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:setFirstPageNumber\\(\\) expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/PageSetup.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Row\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Row.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\CellIterator\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/RowCellIterator.php + + - + message: "#^Class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowIterator implements generic interface Iterator but does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/RowIterator.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\SheetView\\:\\:\\$sheetViewTypes has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/SheetView.php + + - + message: "#^Strict comparison using \\=\\=\\= between int\\ and null will always evaluate to false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/SheetView.php + + - + message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/SheetView.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$invalidCharacters type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$drawingCollection with generic class ArrayObject does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$chartCollection with generic class ArrayObject does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$conditionalStylesCollection type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$protectedCells type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$hyperlinkCollection type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$dataValidationCollection type has no value type specified in iterable type array\\.$#" + 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: "#^Parameter \\#1 \\$pIndex of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension constructor expects int, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$pIndex of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension constructor expects string, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$pRange of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter constructor expects string, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getInvalidCharacters\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getDrawingCollection\\(\\) return type with generic class ArrayObject does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartCollection\\(\\) return type with generic class ArrayObject does not specify its types\\: TKey, TValue$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$input of function array_splice expects array, ArrayObject&iterable\\ given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$pRange 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: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|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: "#^Cannot call method renameCalculationCacheForWorksheet\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getHighestRowAndColumn\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#2 \\$start of function substr expects int, int\\<0, max\\>\\|false given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$pRow of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getRowDimension\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Cannot call method cellExists\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getConditionalStylesCollection\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Result of && is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$pRange of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:setRange\\(\\) expects string, null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getFreezePane\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:removeRow\\(\\) expects string, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$coord of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:coordinateIsRange\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#1 \\$pRange of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:splitRange\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$activeCell \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$selectedCells \\(string\\) does not accept string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:fromArray\\(\\) has parameter \\$source with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:rangeToArray\\(\\) return type has no value type specified in iterable type array\\.$#" + 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 getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|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: "#^Right side of && is always true\\.$#" + 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: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:namedRangeToArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + 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 getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\|null\\.$#" + count: 2 + 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: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:\\$enclosureRequired has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Csv.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:writeLine\\(\\) has parameter \\$pValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Csv.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$cssStyles type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$columnWidths type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$isSpannedCell type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$isBaseCell type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$isSpannedRow type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Call to function array_key_exists\\(\\) with int and array\\('none' \\=\\> 'none', 'dashDot' \\=\\> '1px dashed', 'dashDotDot' \\=\\> '1px dotted', 'dashed' \\=\\> '1px dashed', 'dotted' \\=\\> '1px dotted', 'double' \\=\\> '3px double', 'hair' \\=\\> '1px solid', 'medium' \\=\\> '2px solid', \\.\\.\\.\\) will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:getSheetIndex\\(\\) should return int but returns int\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateMeta\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateMeta\\(\\) has parameter \\$desc with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateMeta\\(\\) has parameter \\$val with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetPrep\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetStarts\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetStarts\\(\\) has parameter \\$rowMin with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetStarts\\(\\) has parameter \\$sheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetTags\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetTags\\(\\) has parameter \\$row with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetTags\\(\\) has parameter \\$tbodyStart with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetTags\\(\\) has parameter \\$theadEnd with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateSheetTags\\(\\) has parameter \\$theadStart with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:extendRowsForCharts\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Cannot access offset 'mime' on array\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$im of function imagepng expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$str of function base64_encode expects string, string\\|false given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Ternary operator condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#3 \\$use_include_path of function fopen expects bool, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#2 \\$length of function fread expects int, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Cannot access offset 0 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Cannot access offset 1 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:buildCssRowHeights\\(\\) has parameter \\$css with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:buildCssPerSheet\\(\\) has parameter \\$css with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:buildCSS\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyle\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleAlignment\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$vAlign of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:mapVAlign\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$hAlign of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:mapHAlign\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleFont\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleBorders\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$borderStyle of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:mapBorderStyle\\(\\) expects int, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleFill\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateHTMLFooter\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTagInline\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTagInline\\(\\) has parameter \\$id with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTagInline\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTag\\(\\) has parameter \\$html with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTag\\(\\) has parameter \\$id with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTag\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableTag\\(\\) has parameter \\$sheetIndex with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateTableFooter\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellCss\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellCss\\(\\) has parameter \\$cellAddress with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellCss\\(\\) has parameter \\$colNum with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellCss\\(\\) has parameter \\$pRow with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellCss\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellDataValueRich\\(\\) has parameter \\$cell with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellDataValueRich\\(\\) has parameter \\$cellData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Parameter \\#1 \\$pStyle of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleFont\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Cannot call method getSuperscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Cannot call method getSubscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellDataValue\\(\\) has parameter \\$cell with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellDataValue\\(\\) has parameter \\$cellData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellDataValue\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellData\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellData\\(\\) has parameter \\$cell with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellData\\(\\) has parameter \\$cellType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellData\\(\\) has parameter \\$cssClass with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowCellData\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowIncludeCharts\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowIncludeCharts\\(\\) has parameter \\$coordinate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowIncludeCharts\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowSpans\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowSpans\\(\\) has parameter \\$colSpan with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowSpans\\(\\) has parameter \\$html with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowSpans\\(\\) has parameter \\$rowSpan with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$cellData with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$cellType with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$colNum with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$colSpan with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$coordinate with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$cssClass with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$html with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$pRow with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$pSheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$rowSpan with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRowWriteCell\\(\\) has parameter \\$sheetIndex with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRow\\(\\) has parameter \\$pValues with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:assembleCSS\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:calculateSpansOmitRows\\(\\) has parameter \\$candidateSpannedRow with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:calculateSpansOmitRows\\(\\) has parameter \\$sheet with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:calculateSpansOmitRows\\(\\) has parameter \\$sheetIndex with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Html.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/IWriter.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\Cell\\\\Style\\:\\:\\$writer has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/Cell/Style.php + + - + message: "#^If condition is always true\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Ods/Cell/Style.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\Content\\:\\:\\$formulaConvertor has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/Content.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Writer/Ods/Content.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<2, max\\> given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Ods/Content.php + + - + message: "#^Parameter \\#1 \\$pRange of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:splitRange\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/Content.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\Formula\\:\\:\\$definedNames has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/Formula.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\NamedExpressions\\:\\:\\$objWriter has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\NamedExpressions\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\NamedExpressions\\:\\:\\$formulaConvertor has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Ods\\\\NamedExpressions\\:\\:__construct\\(\\) has parameter \\$formulaConvertor with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php + + - + message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Ods/NamedExpressions.php + + - + message: "#^Parameter \\#1 \\$content of method XMLWriter\\:\\:text\\(\\) expects string, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Ods/Settings.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Pdf\\:\\:\\$paperSizes type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf.php + + - + message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf/Dompdf.php + + - + message: "#^Parameter \\#2 \\$str of function fwrite expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf/Dompdf.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Pdf\\\\Mpdf\\:\\:createExternalWriterInstance\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf/Mpdf.php + + - + message: "#^Strict comparison using \\=\\=\\= between null and int will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf/Mpdf.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Pdf\\\\Tcpdf\\:\\:createExternalWriterInstance\\(\\) has parameter \\$paperSize with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php + + - + message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:\\$strTable type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:\\$colors type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:\\$IDCLs type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Parameter \\#1 \\$font of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:addFont\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Offset 'startCoordinates' does not exist on array\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Offset 'startOffsetX' does not exist on array\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Offset 'startOffsetY' does not exist on array\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Offset 'endCoordinates' does not exist on array\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Offset 'endOffsetX' does not exist on array\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Offset 'endOffsetY' does not exist on array\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Parameter \\#1 \\$data of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\\\Blip\\:\\:setData\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Parameter \\#1 \\$im of function imagepng expects resource, resource\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Parameter \\#1 \\$im of function imagepng expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Parameter \\#1 \\$blipType of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:setBlipType\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:writeSummaryPropOle\\(\\) has parameter \\$dataSection with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:writeSummaryProp\\(\\) has parameter \\$dataSection with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Parameter \\#2 \\$pad_length of function str_pad expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\BIFFwriter\\:\\:writeEof\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/BIFFwriter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:\\$object has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:\\$data has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:\\$spOffsets type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:\\$spTypes type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^If condition is always true\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Elseif condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:getSpOffsets\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:getSpTypes\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Escher.php + + - + message: "#^Parameter \\#1 \\$name of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:getCharsetFromFontName\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Font.php + + - + message: "#^If condition is always false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Font.php + + - + message: "#^Parameter \\#1 \\$bold of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Font\\:\\:mapBold\\(\\) expects bool, bool\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Font.php + + - + message: "#^Parameter \\#1 \\$underline of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Font\\:\\:mapUnderline\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Font.php + + - + message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:UTF8toBIFF8UnicodeShort\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Font.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$externalSheets type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$references type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$ptg type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$functions type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 5 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:cellToPackedRowcol\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:rangeToPackedRange\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:cellToRowcol\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:advance\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:parenthesizedExpression\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:createTree\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:toReversePolish\\(\\) has parameter \\$tree with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Offset 'left' does not exist on \\(array&nonEmpty\\)\\|string\\.$#" + count: 6 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Offset 'right' does not exist on \\(array&nonEmpty\\)\\|string\\.$#" + count: 5 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Offset 'value' does not exist on \\(array&nonEmpty\\)\\|string\\.$#" + count: 7 + path: src/PhpSpreadsheet/Writer/Xls/Parser.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$palette type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$addedFonts type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$numberFormats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$addedNumberFormats type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$worksheetSizes type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$worksheetOffsets type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$stringTable type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$colors has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:__construct\\(\\) has parameter \\$colors with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:__construct\\(\\) has parameter \\$str_table with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:writeWorkbook\\(\\) has parameter \\$pWorksheetSizes with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:writeAllDefinedNamesBiff8\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Parameter \\#1 \\$pSheet of method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getIndex\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet, PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:writeSupbookInternal\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:writeExternalsheetBiff8\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Cannot access offset 'encoding' on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:writeMsoDrawingGroup\\(\\) has no return typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$escher \\(PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Workbook.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$columnInfo type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$selection type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$stringTable type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$colors has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$fontHashIndex type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:__construct\\(\\) has parameter \\$colors with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:__construct\\(\\) has parameter \\$str_table with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$height of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeRow\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#4 \\$hidden of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeRow\\(\\) expects bool, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getColumn\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getDatatype\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#4 \\$isError of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeBoolErr\\(\\) expects bool, int given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeRichTextString\\(\\) has parameter \\$arrcRun with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$pieces of function implode expects array, array\\\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match_all expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeColinfo\\(\\) has parameter \\$col_array with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$hexadecimal_number of function hexdec expects string, array given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$coordinates of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:indexesFromString\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$activePane \\(int\\) does not accept int\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#5 \\$width of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:positionImage\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#6 \\$height of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:positionImage\\(\\) expects int, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:processBitmapGd\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$im of function imagesx expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$im of function imagesy expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$im of function imagecolorat expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$im of function imagecolorsforindex expects resource, GdImage\\|resource given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$col of function imagecolorsforindex expects int, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$ascii of function chr expects int, float given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:processBitmap\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$length of function fread expects int, int\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#2 \\$data of function unpack expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot access offset 'ident' on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot access offset 'sa' on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot access offset 1 on array\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot access offset 2 on array\\|false\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Cannot access offset 'comp' on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$escher \\(PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:UTF8toBIFF8UnicodeLong\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php + + - + message: "#^Parameter \\#1 \\$fillType of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Xf\\:\\:mapFillType\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xls/Xf.php + + - + message: "#^Parameter \\#1 \\$hAlign of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Xf\\:\\:mapHAlign\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Xf.php + + - + message: "#^Parameter \\#1 \\$vAlign of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Xf\\:\\:mapVAlign\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Xf.php + + - + message: "#^Parameter \\#1 \\$textRotation of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Xf\\:\\:mapTextRotation\\(\\) expects int, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xls/Xf.php + + - + message: "#^Possibly invalid array key type array\\|string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Parameter \\#1 \\$path of function dirname expects string, array\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Argument of an invalid type array\\|null supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Parameter \\#1 \\$path of function basename expects string, array\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Parameter \\#1 \\$function of function call_user_func expects callable\\(\\)\\: mixed, string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:\\$pathNames has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:addZipFiles\\(\\) has parameter \\$zipContent with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:\\$calculateCellValues has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 45 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Result of && is always false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Argument of an invalid type array\\|string supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$yAxisLabel of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#4 \\$id1 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects string, int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#5 \\$id2 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects string, int\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#7 \\$xAxis of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#8 \\$majorGridlines of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#9 \\$minorGridlines of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$xAxisLabel of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#3 \\$id1 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#4 \\$id2 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects string, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#6 \\$yAxis of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Part \\$xAxis\\-\\>getShadowProperty\\('effect'\\) \\(array\\|int\\|string\\|null\\) of encapsed string cannot be cast to string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\|int\\|string given\\.$#" + count: 8 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Part \\$xAxis\\-\\>getShadowProperty\\(\\['color', 'type'\\]\\) \\(array\\|int\\|string\\|null\\) of encapsed string cannot be cast to string\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\|int\\|string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:getChartType\\(\\) never returns string so it can be removed from the return typehint\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:getChartType\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeries and null will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Cannot call method getFillColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Cannot call method getDataValues\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#1 \\$plotSeriesValues of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeBubbles\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues and null will always evaluate to false\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#1 \\$text of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:writeRawData\\(\\) expects array\\\\|string, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, float\\|int given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, float given\\.$#" + count: 6 + path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Comments\\:\\:writeComment\\(\\) has parameter \\$pAuthors with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Comments.php + + - + message: "#^Parameter \\#1 \\$string of function substr expects string, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Comments.php + + - + message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Comments.php + + - + message: "#^Parameter \\#1 \\$arr1 of function array_diff expects array, array\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/ContentTypes.php + + - + message: "#^Cannot access offset 2 on array\\|false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/ContentTypes.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\DefinedNames\\:\\:\\$objWriter has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\DefinedNames\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php + + - + message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/DefinedNames.php + + - + message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/DocProps.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/DocProps.php + + - + message: "#^Parameter \\#1 \\$index of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getChartByIndex\\(\\) expects string, int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php + + - + message: "#^Parameter \\#2 \\$pChart of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Drawing\\:\\:writeChart\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\|false given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php + + - + message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int given\\.$#" + count: 12 + path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 8 + path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Drawing.php + + - + message: "#^Parameter \\#4 \\$pTarget of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeRelationship\\(\\) expects string, array\\|string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Parameter \\#2 \\$pId of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeRelationship\\(\\) expects int, string given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeUnparsedRelationship\\(\\) has parameter \\$relationship with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeUnparsedRelationship\\(\\) has parameter \\$type with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeDrawingHyperLink\\(\\) has parameter \\$i with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeDrawingHyperLink\\(\\) has parameter \\$objWriter with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Parameter \\#2 \\$pId of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeRelationship\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Rels\\:\\:writeDrawingHyperLink\\(\\) should return int but returns float\\|int\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Instanceof between string and PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\RichText will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Instanceof between \\*NEVER\\* and PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\RichText will always evaluate to false\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getName\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, string\\|null given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getItalic\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getSubscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getSuperscript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getStrikethrough\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, float\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Cannot call method getUnderline\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Parameter \\#1 \\$pText of method PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\RichText\\:\\:createTextRun\\(\\) expects string, string\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\StringTable\\:\\:flipStringTable\\(\\) has parameter \\$stringTable with no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\StringTable\\:\\:flipStringTable\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 22 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$pNumberFormat of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Style\\:\\:writeNumFmt\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$pFont of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Style\\:\\:writeFont\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$pFill of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Style\\:\\:writeFill\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$pBorders of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Style\\:\\:writeBorder\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, string\\|null given\\.$#" + count: 4 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, float given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Comparison operation \"\\<\" between int\\ and 0 is always true\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<1, max\\> given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Result of \\|\\| is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Style.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 7 + path: src/PhpSpreadsheet/Writer/Xlsx/Workbook.php + + - + message: "#^Parameter \\#3 \\$pStringTable of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeSheetData\\(\\) expects array\\, array\\\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, string\\|null given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" + count: 19 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<1, max\\> given\\.$#" + count: 7 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeAttributeIf\\(\\) has parameter \\$condition with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeElementIf\\(\\) has parameter \\$condition with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#3 \\$namespace of method XMLWriter\\:\\:startElementNs\\(\\) expects string, null given\\.$#" + count: 8 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^If condition is always true\\.$#" + count: 6 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeDataBarElements\\(\\) has parameter \\$dataBar with no typehint specified\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#4 \\$val of static method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeAttributeIf\\(\\) expects string, int given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, array\\\\|string given\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Argument of an invalid type array\\\\|string supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getCollapsed\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getOutlineLevel\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 3 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#2 \\$content of method XMLWriter\\:\\:writeElement\\(\\) expects string\\|null, int\\|string given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Parameter \\#3 \\$pCell of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeCellFormula\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Right side of && is always true\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Xlfn\\:\\:addXlfn\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:\\$locale has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:providerBinaryComparisonOperation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:testGetFunctions\\(\\) has parameter \\$functionCall with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:providerGetFunctions\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:providerCanLoadAllSupportedLocales\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertCount\\(\\) expects Countable\\|iterable, array\\|bool given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot access offset 2 on array\\|bool\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot access offset 4 on array\\|bool\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 9 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 13 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Argument of an invalid type array\\|bool supplied for foreach, only iterables are supported\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Cannot call method getWorksheet\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:dataProviderBranchPruningFullExecution\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\DefinedNamesCalculationTest\\:\\:namedRangeCalculationTest1\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\DefinedNamesCalculationTest\\:\\:namedRangeCalculationTest2\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:\\$spreadSheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerRangeEvaluation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerNamedRangeEvaluation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerUTF8NamedRangeEvaluation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerCompositeNamedRangeEvaluation\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FormulaAsStringTest\\:\\:providerFunctionsAsString\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DAverageTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DAverageTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DAverageTest\\:\\:providerDAverage\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountATest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountATest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountATest\\:\\:providerDCountA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:database3\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:providerDCount\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DGetTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DGetTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DGetTest\\:\\:providerDGet\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMaxTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMaxTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMaxTest\\:\\:providerDMax\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMinTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMinTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMinTest\\:\\:providerDMin\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DProductTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DProductTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DProductTest\\:\\:providerDProduct\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevPTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevPTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevPTest\\:\\:providerDStDevP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevTest\\:\\:providerDStDev\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DSumTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DSumTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DSumTest\\:\\:providerDSum\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarPTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarPTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarPTest\\:\\:providerDVarP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarTest\\:\\:providerDVar\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$excelCalendar has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$returnDateType has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$sheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DateDifTest\\:\\:providerDATEDIF\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DateTest\\:\\:providerDATE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DateValueTest\\:\\:providerDATEVALUE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DayTest\\:\\:providerDAY\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DayTest\\:\\:providerDAYOpenOffice\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\Days360Test\\:\\:providerDAYS360\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DaysTest\\:\\:providerDAYS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\EDateTest\\:\\:providerEDATE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\EoMonthTest\\:\\:providerEOMONTH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\HourTest\\:\\:providerHOUR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\IsoWeekNumTest\\:\\:providerISOWEEKNUM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\IsoWeekNumTest\\:\\:providerISOWEEKNUM1904\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\MinuteTest\\:\\:providerMINUTE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\MonthTest\\:\\:providerMONTH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\NetworkDaysTest\\:\\:testNETWORKDAYS\\(\\) has parameter \\$arg3 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\NetworkDaysTest\\:\\:providerNETWORKDAYS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\SecondTest\\:\\:providerSECOND\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\TimeTest\\:\\:providerTIME\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\TimeValueTest\\:\\:providerTIMEVALUE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WeekDayTest\\:\\:providerWEEKDAY\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php + + - + message: "#^Parameter \\#1 \\$dateValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WeekDay\\:\\:funcWeekDay\\(\\) expects float\\|int\\|string, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WeekNumTest\\:\\:providerWEEKNUM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WeekNumTest\\:\\:providerWEEKNUM1904\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WorkDayTest\\:\\:testWORKDAY\\(\\) has parameter \\$arg3 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WorkDayTest\\:\\:providerWORKDAY\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\YearFracTest\\:\\:providerYEARFRAC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\YearTest\\:\\:providerYEAR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselITest\\:\\:testBESSELI\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselITest\\:\\:providerBESSELI\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselJTest\\:\\:testBESSELJ\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselJTest\\:\\:providerBESSEJ\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselKTest\\:\\:testBESSELK\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselKTest\\:\\:providerBESSELK\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselYTest\\:\\:testBESSELY\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselYTest\\:\\:providerBESSELY\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2DecTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2DecTest\\:\\:providerBIN2DEC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2HexTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2HexTest\\:\\:providerBIN2HEX\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2OctTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2OctTest\\:\\:providerBIN2OCT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitAndTest\\:\\:providerBITAND\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitLShiftTest\\:\\:providerBITLSHIFT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitOrTest\\:\\:providerBITOR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitRShiftTest\\:\\:providerBITRSHIFT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitXorTest\\:\\:providerBITXOR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ComplexTest\\:\\:testCOMPLEX\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ComplexTest\\:\\:providerCOMPLEX\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ConvertUoMTest\\:\\:testCONVERTUOM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ConvertUoMTest\\:\\:providerCONVERTUOM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2BinTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2BinTest\\:\\:providerDEC2BIN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2HexTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2HexTest\\:\\:providerDEC2HEX\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2OctTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2OctTest\\:\\:providerDEC2OCT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\DeltaTest\\:\\:testDELTA\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\DeltaTest\\:\\:providerDELTA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfCTest\\:\\:testERFC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfCTest\\:\\:providerERFC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfPreciseTest\\:\\:testERFPRECISE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfPreciseTest\\:\\:providerERFPRECISE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfTest\\:\\:testERF\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfTest\\:\\:providerERF\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\GeStepTest\\:\\:testGESTEP\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\GeStepTest\\:\\:providerGESTEP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2BinTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2BinTest\\:\\:providerHEX2BIN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2DecTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2DecTest\\:\\:providerHEX2DEC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2OctTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2OctTest\\:\\:providerHEX2OCT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImAbsTest\\:\\:providerIMABS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImAbsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImArgumentTest\\:\\:providerIMARGUMENT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImArgumentTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImConjugateTest\\:\\:providerIMCONJUGATE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCosTest\\:\\:providerIMCOS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCoshTest\\:\\:providerIMCOSH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCotTest\\:\\:providerIMCOT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCscTest\\:\\:providerIMCSC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCschTest\\:\\:providerIMCSCH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImDivTest\\:\\:testIMDIV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImDivTest\\:\\:providerIMDIV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImExpTest\\:\\:providerIMEXP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImLnTest\\:\\:providerIMLN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImLog10Test\\:\\:providerIMLOG10\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImLog2Test\\:\\:providerIMLOG2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImPowerTest\\:\\:testIMPOWER\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImPowerTest\\:\\:providerIMPOWER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImProductTest\\:\\:testIMPRODUCT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImProductTest\\:\\:providerIMPRODUCT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImRealTest\\:\\:providerIMREAL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImRealTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSecTest\\:\\:providerIMSEC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSechTest\\:\\:providerIMSECH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSinTest\\:\\:providerIMSIN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSinhTest\\:\\:providerIMSINH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSqrtTest\\:\\:providerIMSQRT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSubTest\\:\\:testIMSUB\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSubTest\\:\\:providerIMSUB\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSumTest\\:\\:testIMSUM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSumTest\\:\\:providerIMSUM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImTanTest\\:\\:providerIMTAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImaginaryTest\\:\\:providerIMAGINARY\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImaginaryTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2BinTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2BinTest\\:\\:providerOCT2BIN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2DecTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2DecTest\\:\\:providerOCT2DEC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2HexTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2HexTest\\:\\:providerOCT2HEX\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintMTest\\:\\:testACCRINTM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintMTest\\:\\:providerACCRINTM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintTest\\:\\:testACCRINT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintTest\\:\\:providerACCRINT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorDegRcTest\\:\\:testAMORDEGRC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorDegRcTest\\:\\:providerAMORDEGRC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorLincTest\\:\\:testAMORLINC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorLincTest\\:\\:providerAMORLINC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDayBsTest\\:\\:testCOUPDAYBS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDayBsTest\\:\\:providerCOUPDAYBS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysNcTest\\:\\:testCOUPDAYSNC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysNcTest\\:\\:providerCOUPDAYSNC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysTest\\:\\:testCOUPDAYS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysTest\\:\\:providerCOUPDAYS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNcdTest\\:\\:testCOUPNCD\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNcdTest\\:\\:providerCOUPNCD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNumTest\\:\\:testCOUPNUM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNumTest\\:\\:providerCOUPNUM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupPcdTest\\:\\:testCOUPPCD\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupPcdTest\\:\\:providerCOUPPCD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumIpmtTest\\:\\:testCUMIPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumIpmtTest\\:\\:providerCUMIPMT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumPrincTest\\:\\:testCUMPRINC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumPrincTest\\:\\:providerCUMPRINC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DbTest\\:\\:testDB\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DbTest\\:\\:providerDB\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DdbTest\\:\\:testDDB\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DdbTest\\:\\:providerDDB\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DiscTest\\:\\:testDISC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DiscTest\\:\\:providerDISC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarDeTest\\:\\:testDOLLARDE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarDeTest\\:\\:providerDOLLARDE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarFrTest\\:\\:testDOLLARFR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarFrTest\\:\\:providerDOLLARFR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\EffectTest\\:\\:providerEFFECT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvScheduleTest\\:\\:testFVSCHEDULE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvScheduleTest\\:\\:providerFVSCHEDULE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvTest\\:\\:testFV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvTest\\:\\:providerFV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php + + - + message: "#^Parameter \\#3 \\$message of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) expects string, float given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\HelpersTest\\:\\:providerDaysPerYear\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IPmtTest\\:\\:testIPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IPmtTest\\:\\:providerIPMT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IntRateTest\\:\\:testINTRATE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IntRateTest\\:\\:providerINTRATE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IrrTest\\:\\:testIRR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IrrTest\\:\\:providerIRR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IsPmtTest\\:\\:testISPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IsPmtTest\\:\\:providerISPMT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\MirrTest\\:\\:testMIRR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\MirrTest\\:\\:providerMIRR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NPerTest\\:\\:testNPER\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NPerTest\\:\\:providerNPER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NominalTest\\:\\:providerNOMINAL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NpvTest\\:\\:testNPV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NpvTest\\:\\:providerNPV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PDurationTest\\:\\:testPDURATION\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PDurationTest\\:\\:providerPDURATION\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PmtTest\\:\\:testPMT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PmtTest\\:\\:providerPMT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PpmtTest\\:\\:testPPMT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PpmtTest\\:\\:providerPPMT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceDiscTest\\:\\:testPRICEDISC\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceDiscTest\\:\\:providerPRICEDISC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceMatTest\\:\\:testPRICEMAT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceMatTest\\:\\:providerPRICEMAT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:testPRICE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:providerPRICE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:testPRICE3\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:providerPRICE3\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PvTest\\:\\:testPV\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PvTest\\:\\:providerPV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RateTest\\:\\:testRATE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RateTest\\:\\:providerRATE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\ReceivedTest\\:\\:testRECEIVED\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\ReceivedTest\\:\\:providerRECEIVED\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RriTest\\:\\:testRRI\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RriTest\\:\\:providerRRI\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SlnTest\\:\\:testSLN\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SlnTest\\:\\:providerSLN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SydTest\\:\\:testSYD\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SydTest\\:\\:providerSYD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillEqTest\\:\\:testTBILLEQ\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillEqTest\\:\\:providerTBILLEQ\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillPriceTest\\:\\:testTBILLPRICE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillPriceTest\\:\\:providerTBILLPRICE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillYieldTest\\:\\:testTBILLYIELD\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillYieldTest\\:\\:providerTBILLYIELD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XNpvTest\\:\\:testXNPV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XNpvTest\\:\\:providerXNPV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XirrTest\\:\\:testXIRR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XirrTest\\:\\:providerXIRR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldDiscTest\\:\\:testYIELDDISC\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldDiscTest\\:\\:providerYIELDDISC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldMatTest\\:\\:testYIELDMAT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldMatTest\\:\\:providerYIELDMAT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\AndTest\\:\\:testAND\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\AndTest\\:\\:providerAND\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfErrorTest\\:\\:providerIFERROR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfNaTest\\:\\:providerIFNA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfTest\\:\\:testIF\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfTest\\:\\:providerIF\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfsTest\\:\\:providerIFS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\NotTest\\:\\:testNOT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\NotTest\\:\\:providerNOT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\OrTest\\:\\:testOR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\OrTest\\:\\:providerOR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\SwitchTest\\:\\:testSWITCH\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\SwitchTest\\:\\:providerSwitch\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\XorTest\\:\\:testXOR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\XorTest\\:\\:providerXOR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\AddressTest\\:\\:testADDRESS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\AddressTest\\:\\:providerADDRESS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ChooseTest\\:\\:testCHOOSE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ChooseTest\\:\\:providerCHOOSE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ColumnTest\\:\\:providerCOLUMN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ColumnsTest\\:\\:testCOLUMNS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ColumnsTest\\:\\:providerCOLUMNS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\HLookupTest\\:\\:testHLOOKUP\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\HLookupTest\\:\\:providerHLOOKUP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\IndexTest\\:\\:testINDEX\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\IndexTest\\:\\:providerINDEX\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\IndirectTest\\:\\:providerINDIRECT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\LookupTest\\:\\:testLOOKUP\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\LookupTest\\:\\:providerLOOKUP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\MatchTest\\:\\:testMATCH\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\MatchTest\\:\\:providerMATCH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\OffsetTest\\:\\:providerOFFSET\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\RowTest\\:\\:providerROW\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\RowsTest\\:\\:testROWS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\RowsTest\\:\\:providerROWS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\TransposeTest\\:\\:providerTRANSPOSE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\VLookupTest\\:\\:testVLOOKUP\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\VLookupTest\\:\\:providerVLOOKUP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AbsTest\\:\\:providerAbs\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcosTest\\:\\:providerAcos\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcoshTest\\:\\:providerAcosh\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcotTest\\:\\:providerACOT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcothTest\\:\\:providerACOTH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AllSetupTeardown\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AllSetupTeardown\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AllSetupTeardown\\:\\:\\$sheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ArabicTest\\:\\:providerARABIC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AsinTest\\:\\:providerAsin\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AsinhTest\\:\\:providerAsinh\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\Atan2Test\\:\\:providerATAN2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AtanTest\\:\\:providerAtan\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AtanhTest\\:\\:providerAtanh\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\BaseTest\\:\\:providerBASE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CeilingMathTest\\:\\:providerCEILINGMATH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CeilingPreciseTest\\:\\:providerFLOORPRECISE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CeilingTest\\:\\:providerCEILING\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CombinATest\\:\\:providerCOMBINA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CombinTest\\:\\:providerCOMBIN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CosTest\\:\\:providerCos\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CoshTest\\:\\:providerCosh\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CotTest\\:\\:providerCOT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CothTest\\:\\:providerCOTH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CscTest\\:\\:providerCSC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CschTest\\:\\:providerCSCH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\DegreesTest\\:\\:providerDegrees\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\EvenTest\\:\\:providerEVEN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ExpTest\\:\\:providerEXP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FactDoubleTest\\:\\:providerFACTDOUBLE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FactTest\\:\\:providerFACT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FactTest\\:\\:providerFACTGnumeric\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FloorMathTest\\:\\:providerFLOORMATH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FloorPreciseTest\\:\\:providerFLOORPRECISE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FloorTest\\:\\:providerFLOOR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\GcdTest\\:\\:testGCD\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\GcdTest\\:\\:providerGCD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\IntTest\\:\\:providerINT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LcmTest\\:\\:testLCM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LcmTest\\:\\:providerLCM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LnTest\\:\\:providerLN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\Log10Test\\:\\:providerLN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LogTest\\:\\:providerLOG\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MInverseTest\\:\\:testMINVERSE\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MInverseTest\\:\\:providerMINVERSE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MMultTest\\:\\:testMMULT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MMultTest\\:\\:providerMMULT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MRoundTest\\:\\:providerMROUND\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MdeTermTest\\:\\:providerMDETERM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ModTest\\:\\:providerMOD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MultinomialTest\\:\\:testMULTINOMIAL\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MultinomialTest\\:\\:providerMULTINOMIAL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\OddTest\\:\\:providerODD\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\PowerTest\\:\\:providerPOWER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ProductTest\\:\\:testPRODUCT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ProductTest\\:\\:providerPRODUCT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\QuotientTest\\:\\:providerQUOTIENT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RadiansTest\\:\\:providerRADIANS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RandBetweenTest\\:\\:providerRANDBETWEEN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RomanTest\\:\\:providerROMAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RoundDownTest\\:\\:providerRoundDown\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RoundTest\\:\\:providerRound\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RoundUpTest\\:\\:providerRoundUp\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SecTest\\:\\:providerSEC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SechTest\\:\\:providerSECH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SeriesSumTest\\:\\:testSERIESSUM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SeriesSumTest\\:\\:providerSERIESSUM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SignTest\\:\\:providerSIGN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SinTest\\:\\:providerSin\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SinhTest\\:\\:providerCosh\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SqrtPiTest\\:\\:providerSQRTPI\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SqrtTest\\:\\:providerSqrt\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SubTotalTest\\:\\:providerSUBTOTAL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SubTotalTest\\:\\:providerSUBTOTALHIDDEN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfTest\\:\\:testSUMIF2\\(\\) has parameter \\$array1 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfTest\\:\\:testSUMIF2\\(\\) has parameter \\$array2 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfTest\\:\\:providerSUMIF\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfsTest\\:\\:testSUMIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfsTest\\:\\:providerSUMIFS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumProductTest\\:\\:testSUMPRODUCT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumProductTest\\:\\:providerSUMPRODUCT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumSqTest\\:\\:testSUMSQ\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumSqTest\\:\\:providerSUMSQ\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumTest\\:\\:testSUM\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumTest\\:\\:providerSUM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2MY2Test\\:\\:testSUMX2MY2\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2MY2Test\\:\\:testSUMX2MY2\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2MY2Test\\:\\:providerSUMX2MY2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2PY2Test\\:\\:testSUMX2PY2\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2PY2Test\\:\\:testSUMX2PY2\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2PY2Test\\:\\:providerSUMX2PY2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumXMY2Test\\:\\:testSUMXMY2\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumXMY2Test\\:\\:testSUMXMY2\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumXMY2Test\\:\\:providerSUMXMY2\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\TanTest\\:\\:providerTan\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\TanhTest\\:\\:providerTanh\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\TruncTest\\:\\:providerTRUNC\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AveDevTest\\:\\:testAVEDEV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AveDevTest\\:\\:providerAVEDEV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageATest\\:\\:testAVERAGEA\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageATest\\:\\:providerAVERAGEA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfTest\\:\\:testAVERAGEIF\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfTest\\:\\:providerAVERAGEIF\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfsTest\\:\\:testAVERAGEIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfsTest\\:\\:providerAVERAGEIFS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageTest\\:\\:testAVERAGE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageTest\\:\\:providerAVERAGE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaDistTest\\:\\:testBETADIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaDistTest\\:\\:providerBETADIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaInvTest\\:\\:testBETAINV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaInvTest\\:\\:providerBETAINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistRangeTest\\:\\:testBINOMDISTRANGE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistRangeTest\\:\\:providerBINOMDISTRANGE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistTest\\:\\:testBINOMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistTest\\:\\:providerBINOMDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomInvTest\\:\\:testBINOMINV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomInvTest\\:\\:providerBINOMINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistLeftTailTest\\:\\:testCHIDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistLeftTailTest\\:\\:providerCHIDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistRightTailTest\\:\\:testCHIDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistRightTailTest\\:\\:providerCHIDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiInvLeftTailTest\\:\\:providerCHIINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiInvRightTailTest\\:\\:providerCHIINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiTestTest\\:\\:providerCHITEST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ConfidenceTest\\:\\:testCONFIDENCE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ConfidenceTest\\:\\:providerCONFIDENCE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CorrelTest\\:\\:providerCORREL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CorrelTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountATest\\:\\:testCOUNTA\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountATest\\:\\:providerCOUNTA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountBlankTest\\:\\:testCOUNTBLANK\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountBlankTest\\:\\:providerCOUNTBLANK\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfTest\\:\\:testCOUNTIF\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfTest\\:\\:providerCOUNTIF\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfsTest\\:\\:testCOUNTIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfsTest\\:\\:providerCOUNTIFS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testBasicCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerBasicCOUNT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testExcelCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerExcelCOUNT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testOpenOfficeCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerOpenOfficeCOUNT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testGnumericCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerGnumericCOUNT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CovarTest\\:\\:testCOVAR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CovarTest\\:\\:providerCOVAR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ExponDistTest\\:\\:testEXPONDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ExponDistTest\\:\\:providerEXPONDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FDistTest\\:\\:testFDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FDistTest\\:\\:providerFDIST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FisherInvTest\\:\\:providerFISHERINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FisherTest\\:\\:providerFISHER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ForecastTest\\:\\:testFORECAST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ForecastTest\\:\\:providerFORECAST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaDistTest\\:\\:testGAMMADIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaDistTest\\:\\:providerGAMMADIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaInvTest\\:\\:testGAMMAINV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaInvTest\\:\\:providerGAMMAINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaLnTest\\:\\:providerGAMMALN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaTest\\:\\:providerGAMMA\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GaussTest\\:\\:providerGAUSS\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GaussTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GeoMeanTest\\:\\:testGEOMEAN\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GeoMeanTest\\:\\:providerGEOMEAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GrowthTest\\:\\:testGROWTH\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GrowthTest\\:\\:providerGROWTH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HarMeanTest\\:\\:testHARMEAN\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HarMeanTest\\:\\:providerHARMEAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HypGeomDistTest\\:\\:testHYPGEOMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HypGeomDistTest\\:\\:providerHYPGEOMDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\InterceptTest\\:\\:testINTERCEPT\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\InterceptTest\\:\\:testINTERCEPT\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\InterceptTest\\:\\:providerINTERCEPT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\KurtTest\\:\\:testKURT\\(\\) has parameter \\$values with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\KurtTest\\:\\:providerKURT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LargeTest\\:\\:providerLARGE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php + + - + message: "#^Cannot access offset int on array\\|int\\|string\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LinEstTest\\:\\:providerLINEST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php + + - + message: "#^Cannot access offset int on array\\|int\\|string\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogEstTest\\:\\:providerLOGEST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogInvTest\\:\\:testLOGINV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogInvTest\\:\\:providerLOGINV\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDist2Test\\:\\:testLOGNORMDIST2\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDist2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDist2Test\\:\\:providerLOGNORMDIST2\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDist2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDistTest\\:\\:testLOGNORMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDistTest\\:\\:providerLOGNORMDIST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxATest\\:\\:testMAXA\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxATest\\:\\:providerMAXA\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxIfsTest\\:\\:testMAXIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxIfsTest\\:\\:providerMAXIFS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxTest\\:\\:testMAX\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxTest\\:\\:providerMAX\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MedianTest\\:\\:testMEDIAN\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MedianTest\\:\\:providerMEDIAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinATest\\:\\:testMINA\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinATest\\:\\:providerMINA\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinIfsTest\\:\\:testMINIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinIfsTest\\:\\:providerMINIFS\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinTest\\:\\:testMIN\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinTest\\:\\:providerMIN\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ModeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ModeTest\\:\\:providerMODE\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ModeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NegBinomDistTest\\:\\:testNEGBINOMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NegBinomDistTest\\:\\:providerNEGBINOMDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormDistTest\\:\\:testNORMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormDistTest\\:\\:providerNORMDIST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormInvTest\\:\\:testNORMINV\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormInvTest\\:\\:providerNORMINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSDist2Test\\:\\:testNORMSDIST2\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSDist2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSDist2Test\\:\\:providerNORMSDIST2\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSDist2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSDistTest\\:\\:providerNORMSDIST\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSInvTest\\:\\:providerNORMSINV\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSInvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PercentRankTest\\:\\:providerPERCENTRANK\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PercentileTest\\:\\:testPERCENTILE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PercentileTest\\:\\:providerPERCENTILE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutTest\\:\\:testPERMUT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutTest\\:\\:providerPERMUT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutationATest\\:\\:testPERMUT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutationATest\\:\\:providerPERMUT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PoissonTest\\:\\:testPOISSON\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PoissonTest\\:\\:providerPOISSON\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\QuartileTest\\:\\:testQUARTILE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\QuartileTest\\:\\:providerQUARTILE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RankTest\\:\\:providerRANK\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RsqTest\\:\\:testRSQ\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RsqTest\\:\\:testRSQ\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RsqTest\\:\\:providerRSQ\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SkewTest\\:\\:testSKEW\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SkewTest\\:\\:providerSKEW\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SlopeTest\\:\\:testSLOPE\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SlopeTest\\:\\:testSLOPE\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SlopeTest\\:\\:providerSLOPE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SmallTest\\:\\:providerSMALL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevATest\\:\\:providerSTDEVA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevATest\\:\\:providerOdsSTDEVA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPATest\\:\\:providerSTDEVPA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPATest\\:\\:providerOdsSTDEVPA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPTest\\:\\:providerSTDEVP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPTest\\:\\:providerOdsSTDEVP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevTest\\:\\:providerSTDEV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevTest\\:\\:providerOdsSTDEV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StandardizeTest\\:\\:testSTANDARDIZE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StandardizeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StandardizeTest\\:\\:providerSTANDARDIZE\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StandardizeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SteyxTest\\:\\:testSTEYX\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SteyxTest\\:\\:testSTEYX\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SteyxTest\\:\\:providerSTEYX\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TDistTest\\:\\:providerTDIST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TinvTest\\:\\:providerTINV\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrendTest\\:\\:testTREND\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrendTest\\:\\:providerGROWTH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrimMeanTest\\:\\:testTRIMMEAN\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrimMeanTest\\:\\:providerTRIMMEAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarATest\\:\\:providerVARA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarATest\\:\\:providerOdsVARA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPATest\\:\\:providerVARPA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPATest\\:\\:providerOdsVARPA\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPTest\\:\\:providerVARP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPTest\\:\\:providerOdsVARP\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarTest\\:\\:providerVAR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarTest\\:\\:providerOdsVAR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\WeibullTest\\:\\:providerWEIBULL\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ZTestTest\\:\\:providerZTEST\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\CharTest\\:\\:providerCHAR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\CleanTest\\:\\:providerCLEAN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\CodeTest\\:\\:providerCODE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ConcatenateTest\\:\\:testCONCATENATE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ConcatenateTest\\:\\:providerCONCATENATE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\DollarTest\\:\\:testDOLLAR\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\DollarTest\\:\\:providerDOLLAR\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ExactTest\\:\\:testEXACT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ExactTest\\:\\:providerEXACT\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FindTest\\:\\:testFIND\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FindTest\\:\\:providerFIND\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FixedTest\\:\\:testFIXED\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FixedTest\\:\\:providerFIXED\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LeftTest\\:\\:testLEFT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LeftTest\\:\\:providerLEFT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LeftTest\\:\\:providerLocaleLEFT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LenTest\\:\\:providerLEN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LowerTest\\:\\:providerLOWER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LowerTest\\:\\:providerLocaleLOWER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\MidTest\\:\\:testMID\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\MidTest\\:\\:providerMID\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\MidTest\\:\\:providerLocaleMID\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\NumberValueTest\\:\\:testNUMBERVALUE\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\NumberValueTest\\:\\:providerNUMBERVALUE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ProperTest\\:\\:providerPROPER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ProperTest\\:\\:providerLocaleLOWER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ReplaceTest\\:\\:testREPLACE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ReplaceTest\\:\\:providerREPLACE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ReptTest\\:\\:providerREPT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\RightTest\\:\\:testRIGHT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\RightTest\\:\\:providerRIGHT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\RightTest\\:\\:providerLocaleRIGHT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SearchTest\\:\\:testSEARCH\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SearchTest\\:\\:providerSEARCH\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SubstituteTest\\:\\:testSUBSTITUTE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SubstituteTest\\:\\:providerSUBSTITUTE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TTest\\:\\:providerT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextJoinTest\\:\\:testTEXTJOIN\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextJoinTest\\:\\:providerTEXTJOIN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextTest\\:\\:testTEXT\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextTest\\:\\:providerTEXT\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TrimTest\\:\\:providerTRIM\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\UpperTest\\:\\:providerUPPER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\UpperTest\\:\\:providerLocaleLOWER\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:\\$currencyCode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:providerVALUE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Web\\\\WebServiceTest\\:\\:testWEBSERVICE\\(\\) has parameter \\$responseData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Web/WebServiceTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Web\\\\WebServiceTest\\:\\:providerWEBSERVICE\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/Web/WebServiceTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:\\$returnDate has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsBlank\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsBlank\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsErr\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsErr\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsError\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsError\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testErrorType\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerErrorType\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsLogical\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsLogical\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsNa\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsNa\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsNumber\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsNumber\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsText\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsNonText\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsNonText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsEven\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsEven\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsOdd\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsOdd\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testTYPE\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerTYPE\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testN\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerN\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsFormula\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIfCondition\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIfCondition\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\LookupRefTest\\:\\:providerFormulaText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\TranslationTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/TranslationTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\TranslationTest\\:\\:\\$returnDate has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/TranslationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\TranslationTest\\:\\:providerTranslations\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/TranslationTest.php + + - + message: "#^Cannot call method setAutoSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerR1C1ConversionToA1Absolute\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerR1C1ConversionToA1Relative\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerR1C1ConversionToA1Exception\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerA1ConversionToR1C1Absolute\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerA1ConversionToR1C1Relative\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerA1ConversionToR1C1Exception\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:\\$currencyCode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:currencyProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:fractionProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:percentageProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:timeProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:stringProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Cell/CellTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CellTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CellTest\\:\\:providerSetValueExplicit\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CellTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CellTest\\:\\:providerSetValueExplicitException\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CellTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CellTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerColumnString\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerColumnIndex\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerCoordinates\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:testIndexesFromString\\(\\) has parameter \\$expectedResult with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerIndexesFromString\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerAbsoluteCoordinates\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerAbsoluteReferences\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerSplitRange\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerBuildRange\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Parameter \\#1 \\$pRange of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:buildRange\\(\\) expects array, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerRangeBoundaries\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerRangeDimension\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerGetRangeBoundaries\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:testExtractAllCellReferencesInRange\\(\\) has parameter \\$expectedResult with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerExtractAllCellReferencesInRange\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerInvalidRange\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerMergeRangesInCollection\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerCoordinateIsRange\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php + + - + message: "#^Parameter \\#1 \\$string of function strlen expects string, PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\RichText\\|string\\|null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/DataTypeTest.php + + - + message: "#^Cannot call method hasValidValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 9 + path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php + + - + message: "#^Cannot call method getDataValidation\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 8 + path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\DefaultValueBinderTest\\:\\:createCellStub\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\DefaultValueBinderTest\\:\\:binderProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\DefaultValueBinderTest\\:\\:providerDataTypeForValue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php + + - + message: "#^Parameter \\#1 \\$pUrl of class PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Hyperlink constructor expects string, null given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Cell/HyperlinkTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\ValueBinderWithOverriddenDataTypeForValue\\:\\:\\$called has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php + + - + message: "#^Parameter \\#1 \\$overlay of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:setOverlay\\(\\) expects bool, string given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Chart/LegendTest.php + + - + message: "#^Parameter \\#2 \\$cell of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:add\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + + - + message: "#^Cannot call method getParent\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + + - + message: "#^Cannot call method getCoordinate\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + + - + message: "#^Parameter \\#1 \\$cell of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:update\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + + - + message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getHighestColumn\\(\\) expects string\\|null, int given\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:\\$errorMessage has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:testExpectedExceptions\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:testExpectedExceptions\\(\\) has parameter \\$actual with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:testExpectedExceptions\\(\\) has parameter \\$expected with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has parameter \\$actual with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has parameter \\$delta with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has parameter \\$expected with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has parameter \\$actual with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has parameter \\$delta with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has parameter \\$expected with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Result of \\|\\| is always false\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:getErrorMessage\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedRange\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedFormula\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DefinedNameFormulaTest\\:\\:providerRangeOrFormula\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/DefinedNameTest.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 20 + path: tests/PhpSpreadsheetTests/DefinedNameTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 14 + path: tests/PhpSpreadsheetTests/DefinedNameTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/DefinedNameTest.php + + - + message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/DefinedNameTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:\\$properties has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:providerCreationTime\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:providerModifiedTime\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:testSetCustomProperties\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:providerCustomProperties\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:testGenerateFunctionListByName\\(\\) has parameter \\$phpSpreadsheetFunctions with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:testGenerateFunctionListByCategory\\(\\) has parameter \\$phpSpreadsheetFunctions with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:providerGenerateFunctionListByName\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:providerGenerateFunctionListByCategory\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ActiveSheetTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ColumnWidthTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ColumnWidthTest\\:\\:testReadColumnWidth\\(\\) has parameter \\$format with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php + + - + message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php + + - + message: "#^Cannot call method getWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\CommentsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\CommentsTest\\:\\:testComments\\(\\) has parameter \\$format with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ConditionalStopIfTrueTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:addCondition\\(\\) expects string, float given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php + + - + message: "#^Cannot call method setAutoSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ConditionalTextTest.php + + - + message: "#^Parameter \\#1 \\$im of function imagecolorallocate expects resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php + + - + message: "#^Parameter \\#1 \\$im of function imagestring expects resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php + + - + message: "#^Parameter \\#6 \\$col of function imagestring expects int, int\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\MemoryDrawing\\:\\:setImageResource\\(\\) expects GdImage\\|resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php + + - + message: "#^Cannot call method getUrl\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Hyperlink\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\EnclosureTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\FreezePaneTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/FreezePaneTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\MergedCellsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/MergedCellsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\PrintAreaTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php + + - + message: "#^Cannot call method getPageSetup\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadBlankCellsTest\\:\\:providerSheetFormat\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadFilterTest\\:\\:providerCellsValues\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadFilterTest\\:\\:testXlsxLoadWithoutReadFilter\\(\\) has parameter \\$arrayData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadFilterTest\\:\\:testXlsxLoadWithReadFilter\\(\\) has parameter \\$arrayData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\SelectedCellsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/SelectedCellsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\StreamTest\\:\\:providerFormats\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/StreamTest.php + + - + message: "#^Cannot access offset 'size' on array\\(0 \\=\\> int, 1 \\=\\> int, 2 \\=\\> int, 3 \\=\\> int, 4 \\=\\> int, 5 \\=\\> int, 6 \\=\\> int, 7 \\=\\> int, \\.\\.\\.\\)\\|false\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Functional/StreamTest.php + + - + message: "#^Parameter \\#1 \\$fp of function fstat expects resource, resource\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Functional/StreamTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/StreamTest.php + + - + message: "#^Parameter \\#1 \\$fp of function ftell expects resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/StreamTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\TypeAttributePreservationTest\\:\\:providerFormulae\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\TypeAttributePreservationTest\\:\\:testFormulae\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php + + - + message: "#^Cannot call method getOldCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\WorkbookViewAttributesTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Functional/WorkbookViewAttributesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Helper\\\\HtmlTest\\:\\:providerUtf8EncodingSupport\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Helper/HtmlTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Helper\\\\SampleTest\\:\\:providerSample\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Helper/SampleTest.php + + - + message: "#^Parameter \\#1 \\$expected of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) expects class\\-string\\, string given\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/IOFactoryTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\IOFactoryTest\\:\\:providerCreateWriter\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/IOFactoryTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\IOFactoryTest\\:\\:providerCreateReader\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/IOFactoryTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\IOFactoryTest\\:\\:providerIdentify\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/IOFactoryTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedFormula\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/NamedFormulaTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedRange\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/NamedRangeTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:\\$startRow has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:\\$endRow has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:\\$filterType has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:setFilterType\\(\\) has parameter \\$type with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter1\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter1\\(\\) has parameter \\$row with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter0\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:filter0\\(\\) has parameter \\$row with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousTest\\:\\:\\$inputFileName has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 13 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerDelimiterDetection\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerCanLoad\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerEncodings\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerEscapes\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerGuessEncoding\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 10 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 67 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php + + - + message: "#^Cannot call method getVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerBorderStyle\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerFillType\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerHorizontal\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerUnderline\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerVertical\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerDataType\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Html\\\\HtmlBorderTest\\:\\:providerBorderStyle\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php + + - + message: "#^Parameter \\#1 \\$file of function file_put_contents expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Html\\\\HtmlHelper\\:\\:createHtml\\(\\) should return string but returns string\\|false\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 7 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlLoadStringTest.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 50 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php + + - + message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Html\\\\HtmlTest\\:\\:providerCanReadVerySmallFile\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 16 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php + + - + message: "#^Cannot call method getWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php + + - + message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\OdsTest\\:\\:\\$timeZone has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 16 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 14 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupBug1772Test\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupBug1772Test\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:testValidXML\\(\\) has parameter \\$libxmlDisableEntityLoader with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:providerValidXML\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:testInvalidXML\\(\\) has parameter \\$libxmlDisableEntityLoader with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:providerInvalidXML\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:providerValidXMLForCallback\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\SlkTest\\:\\:\\$testbook has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/SlkTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\SlkTest\\:\\:\\$filename has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/SlkTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 52 + path: tests/PhpSpreadsheetTests/Reader/SlkTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 7 + path: tests/PhpSpreadsheetTests/Reader/SlkTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/SlkTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xls\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xls\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Reader/XlsTest.php + + - + message: "#^Cannot call method getCoordinate\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\AutoFilterTest\\:\\:getWorksheetInstance\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\AutoFilterTest\\:\\:getXMLInstance\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\AutoFilterTest\\:\\:getXMLInstance\\(\\) has parameter \\$ref with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\AutoFilterTest\\:\\:getAutoFilterInstance\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\AutoFilterTest\\:\\:loadDataProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php + + - + message: "#^Function PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\getTitleText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php + + - + message: "#^Function PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\getTitleText\\(\\) has parameter \\$title with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method setMinimumConditionalFormatValueObject\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getMinimumConditionalFormatValueObject\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" + count: 13 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getMaximumConditionalFormatValueObject\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" + count: 13 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getConditionalFormattingRuleExt\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" + count: 8 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getShowValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/NamedRangeTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php + + - + message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Cannot call method getVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Cannot call method getWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Cannot call method getVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Cannot call method hasDataValidation\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\XlsxTest\\:\\:testStripsWhiteSpaceFromStyleString\\(\\) has parameter \\$string with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\XlsxTest\\:\\:providerStripsWhiteSpaceFromStyleString\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 11 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlOddTest\\:\\:\\$filename has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php + + - + message: "#^Parameter \\#1 \\$file of function file_put_contents expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlStyleCoverageTest\\:\\:providerBorderStyle\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlStyleCoverageTest\\:\\:providerFillType\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 70 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlStylesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlTest\\:\\:testInvalidSimpleXML\\(\\) has parameter \\$filename with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlTest\\:\\:providerInvalidSimpleXML\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php + + - + message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php + + - + message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\ReferenceHelperTest\\:\\:providerFormulaUpdates\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/ReferenceHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\ReferenceHelperTest\\:\\:providerMultipleWorksheetFormulaUpdates\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/ReferenceHelperTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\CodePageTest\\:\\:providerCodePage\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/CodePageTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:\\$excelCalendar has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:\\$dttimezone has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeExcelToTimestamp1900\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeTimestampToExcel1900\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeDateTimeToExcel\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:testDateTimeFormattedPHPToExcel1900\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeFormattedPHPToExcel1900\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeExcelToTimestamp1904\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeTimestampToExcel1904\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:testIsDateTimeFormatCode\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerIsDateTimeFormatCode\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeExcelToTimestamp1900Timezone\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Shared/DateTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\FontTest\\:\\:providerFontSizeToPixels\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/FontTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\FontTest\\:\\:providerInchSizeToPixels\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/FontTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\FontTest\\:\\:providerCentimeterSizeToPixels\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/FontTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\PasswordHasherTest\\:\\:testHashPassword\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\PasswordHasherTest\\:\\:providerHashPassword\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\StringHelperTest\\:\\:\\$currencyCode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\StringHelperTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\StringHelperTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php + + - + message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:setCurrencyCode\\(\\) expects string, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\TimeZoneTest\\:\\:\\$tztimezone has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\TimeZoneTest\\:\\:\\$dttimezone has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php + + - + message: "#^Cannot call method getTimestamp\\(\\) on DateTime\\|false\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php + + - + message: "#^Parameter \\#1 \\$timezone of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\TimeZone\\:\\:getTimeZoneAdjustment\\(\\) expects string, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\Trend\\\\ExponentialBestFitTest\\:\\:providerExponentialBestFit\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\Trend\\\\LinearBestFitTest\\:\\:providerLinearBestFit\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\SpreadsheetTest\\:\\:dataProviderForSheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\SpreadsheetTest\\:\\:testGetSheetByName\\(\\) has parameter \\$index with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\SpreadsheetTest\\:\\:testGetSheetByName\\(\\) has parameter \\$sheetName with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/SpreadsheetTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 9 + path: tests/PhpSpreadsheetTests/Style/AlignmentTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 29 + path: tests/PhpSpreadsheetTests/Style/AlignmentTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 65 + path: tests/PhpSpreadsheetTests/Style/BorderTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testGetRed\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorGetRed\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testGetGreen\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorGetGreen\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testGetBlue\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorGetBlue\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testChangeBrightness\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorChangeBrightness\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ColorTest.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:addCondition\\(\\) expects string, float given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Style/ConditionalTest.php + + - + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:setConditions\\(\\) expects array\\\\|bool\\|float\\|int\\|string, array\\ given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/ConditionalTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 10 + path: tests/PhpSpreadsheetTests/Style/ExportArrayTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 10 + path: tests/PhpSpreadsheetTests/Style/ExportArrayTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Style/ExportArrayTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/FontTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/FontTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php + + - + message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:\\$currencyCode has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:testFormatValueWithMask\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:providerNumberFormat\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:testFormatValueWithMaskDate\\(\\) has parameter \\$args with no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:providerNumberFormatDates\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Style/StyleTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\Column\\\\RuleTest\\:\\:\\$testAutoFilterRuleObject has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\Column\\\\RuleTest\\:\\:\\$mockAutoFilterColumnObject has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\ColumnTest\\:\\:\\$testInitialColumn has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\ColumnTest\\:\\:\\$testAutoFilterColumnObject has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\ColumnTest\\:\\:\\$mockAutoFilterObject has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilterTest\\:\\:\\$testInitialRange has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilterTest\\:\\:\\$mockWorksheetObject has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilterTest\\:\\:\\$cellCollection has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php + + - + message: "#^Parameter \\#1 \\$pColumn of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:setColumn\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\|string, float given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIterator2Test\\:\\:providerExistingCell\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIterator2Test\\:\\:providerEmptyColumn\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIteratorTest\\:\\:\\$mockCell has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnIteratorTest\\:\\:\\$mockColumn has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnTest\\:\\:\\$mockColumn has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php + + - + message: "#^Parameter \\#1 \\$im of function imagecolorallocate expects resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php + + - + message: "#^Parameter \\#1 \\$im of function imagestring expects resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php + + - + message: "#^Parameter \\#6 \\$col of function imagestring expects int, int\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php + + - + message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\MemoryDrawing\\:\\:setImageResource\\(\\) expects GdImage\\|resource, resource\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\PageMarginsTest\\:\\:providerPointsAndInches\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\PageMarginsTest\\:\\:providerCentimetersAndInches\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\PageMarginsTest\\:\\:providerMillimetersAndInches\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIterator2Test\\:\\:providerExistingCell\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php + + - + message: "#^Parameter \\#2 \\$rowIndex of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowCellIterator constructor expects int, string given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIterator2Test\\:\\:providerEmptyRow\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIteratorTest\\:\\:\\$mockCell has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowIteratorTest\\:\\:\\$mockRow has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowTest\\:\\:\\$mockRow has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/RowTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetNamedRangesTest\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php + + - + message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:setTitleInvalidProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:setCodeNameInvalidProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:extractSheetTitleProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:removeColumnProvider\\(\\) return type has no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveColumn\\(\\) has parameter \\$expectedData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveColumn\\(\\) has parameter \\$initialData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:removeRowsProvider\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveRows\\(\\) has parameter \\$expectedData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveRows\\(\\) has parameter \\$initialData with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Csv\\\\CsvEnclosureTest\\:\\:\\$cellValues has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 11 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php + + - + message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\CallbackTest\\:\\:yellowBody\\(\\) should return string but returns string\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php + + - + message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php + + - + message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php + + - + message: "#^Cannot call method getColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php + + - + message: "#^Cannot call method setSuperScript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php + + - + message: "#^Cannot call method setSubScript\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php + + - + message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlCommentsTest\\:\\:\\$spreadsheet has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlCommentsTest\\:\\:providerCommentRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php + + - + message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:\\$currency has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:\\$decsep has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:\\$thosep has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:providerNumberFormat\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:providerNumberFormatDates\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\ImagesRootTest\\:\\:\\$curdir has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Html/InvalidFileNameTest.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/VisibilityTest.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Html/VisibilityTest.php + + - + message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/VisibilityTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\XssVulnerabilityTest\\:\\:providerAcceptableMarkupRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\XssVulnerabilityTest\\:\\:providerXssRichText\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringNotContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Ods\\\\ContentTest\\:\\:\\$samplesPath has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\RetainSelectedCellsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:testAddColor\\(\\) has parameter \\$expectedResult with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:testAddColor\\(\\) has parameter \\$testColors with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:providerAddColor\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:paletteToColor\\(\\) has parameter \\$palette with no value type specified in iterable type array\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\XlsGifBmpTest\\:\\:\\$filename has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xls/XlsGifBmpTest.php + + - + message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xlsx\\\\FloatsRetainedTest\\:\\:providerIntyFloatsRetainedByWriter\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xlsx\\\\LocaleFloatsTest\\:\\:\\$localeAdjusted has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php + + - + message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xlsx\\\\LocaleFloatsTest\\:\\:\\$currentLocale has no typehint specified\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php + + - + message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php + + - + message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Parameter \\#1 \\$filename of method ZipArchive\\:\\:open\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php + + - + message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Parameter \\#1 \\$filename of method ZipArchive\\:\\:open\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Cannot call method getDrawingCollection\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php + + - + message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Parameter \\#1 \\$filename of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertFileExists\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Parameter \\#1 \\$filename of method ZipArchive\\:\\:open\\(\\) expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" + count: 8 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Parameter \\#1 \\$data of function simplexml_load_string expects string, string\\|false given\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Cannot access property \\$workbookProtection on SimpleXMLElement\\|false\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Cannot access property \\$sheets on SimpleXMLElement\\|false\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Cannot access property \\$pageSetup on SimpleXMLElement\\|false\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Cannot access property \\$sheetProtection on SimpleXMLElement\\|false\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php + + - + message: "#^Function calculationTestDataGenerator\\(\\) has no return typehint specified\\.$#" + count: 1 + path: tests/data/Calculation/Calculation.php + + - + message: "#^Comparison operation \"\\>\" between 1 and 0 is always true\\.$#" + count: 4 + path: tests/data/Calculation/Logical/XOR.php + + - + message: "#^Comparison operation \"\\>\" between 2 and 0 is always true\\.$#" + count: 4 + path: tests/data/Calculation/Logical/XOR.php + + - + message: "#^Comparison operation \"\\>\" between 0 and 1 is always false\\.$#" + count: 5 + path: tests/data/Calculation/Logical/XOR.php + + - + message: "#^Comparison operation \"\\>\" between 0 and 2 is always false\\.$#" + count: 2 + path: tests/data/Calculation/Logical/XOR.php + + - + message: "#^Comparison operation \"\\>\" between 3 and 0 is always true\\.$#" + count: 1 + path: tests/data/Calculation/Logical/XOR.php + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 6917c78c..f39ce395 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,8 @@ +includes: + - phpstan-baseline.neon + parameters: - level: 3 + level: max paths: - src/ - tests/ From 49f87de16539e9b6e3c427ee8534c45c4ffd1f40 Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Mon, 12 Apr 2021 11:10:23 +0900 Subject: [PATCH 179/187] Reduce PHPStan error in tests --- composer.json | 1 + composer.lock | 57 +- phpstan-baseline.neon | 7052 ++--------------- phpstan.neon.dist | 8 +- .../20_Reader_worksheet_hyperlink_image.php | 3 +- .../Calculation/DateTimeExcel/WeekDay.php | 2 +- src/PhpSpreadsheet/Chart/Legend.php | 10 +- src/PhpSpreadsheet/Collection/Cells.php | 6 +- src/PhpSpreadsheet/Shared/File.php | 11 + .../Calculation/CalculationTest.php | 21 +- .../DefinedNameConfusedForCellTest.php | 11 +- .../Calculation/Engine/RangeTest.php | 13 +- .../Calculation/FormulaAsStringTest.php | 2 +- .../Functions/Database/DAverageTest.php | 6 +- .../Functions/Database/DCountATest.php | 6 +- .../Functions/Database/DCountTest.php | 8 +- .../Functions/Database/DGetTest.php | 6 +- .../Functions/Database/DMaxTest.php | 6 +- .../Functions/Database/DMinTest.php | 6 +- .../Functions/Database/DProductTest.php | 6 +- .../Functions/Database/DStDevPTest.php | 6 +- .../Functions/Database/DStDevTest.php | 6 +- .../Functions/Database/DSumTest.php | 6 +- .../Functions/Database/DVarPTest.php | 6 +- .../Functions/Database/DVarTest.php | 6 +- .../Functions/DateTime/AllSetupTeardown.php | 24 +- .../Functions/DateTime/DateDifTest.php | 2 +- .../Functions/DateTime/DateTest.php | 2 +- .../Functions/DateTime/DateValueTest.php | 2 +- .../Functions/DateTime/DayTest.php | 4 +- .../Functions/DateTime/Days360Test.php | 2 +- .../Functions/DateTime/DaysTest.php | 2 +- .../Functions/DateTime/EDateTest.php | 2 +- .../Functions/DateTime/EoMonthTest.php | 2 +- .../Functions/DateTime/HourTest.php | 2 +- .../Functions/DateTime/IsoWeekNumTest.php | 4 +- .../Functions/DateTime/MinuteTest.php | 2 +- .../Functions/DateTime/MonthTest.php | 2 +- .../Functions/DateTime/NetworkDaysTest.php | 2 +- .../Functions/DateTime/SecondTest.php | 2 +- .../Functions/DateTime/TimeTest.php | 2 +- .../Functions/DateTime/TimeValueTest.php | 2 +- .../Functions/DateTime/WeekDayTest.php | 2 +- .../Functions/DateTime/WeekNumTest.php | 4 +- .../Functions/DateTime/WorkDayTest.php | 2 +- .../Functions/DateTime/YearFracTest.php | 2 +- .../Functions/DateTime/YearTest.php | 2 +- .../Functions/Engineering/BesselITest.php | 2 +- .../Functions/Engineering/BesselJTest.php | 2 +- .../Functions/Engineering/BesselKTest.php | 2 +- .../Functions/Engineering/BesselYTest.php | 2 +- .../Functions/Engineering/Bin2DecTest.php | 5 +- .../Functions/Engineering/Bin2HexTest.php | 5 +- .../Functions/Engineering/Bin2OctTest.php | 5 +- .../Functions/Engineering/BitAndTest.php | 2 +- .../Functions/Engineering/BitLShiftTest.php | 2 +- .../Functions/Engineering/BitOrTest.php | 2 +- .../Functions/Engineering/BitRShiftTest.php | 2 +- .../Functions/Engineering/BitXorTest.php | 2 +- .../Functions/Engineering/ComplexTest.php | 2 +- .../Functions/Engineering/ConvertUoMTest.php | 2 +- .../Functions/Engineering/Dec2BinTest.php | 5 +- .../Functions/Engineering/Dec2HexTest.php | 5 +- .../Functions/Engineering/Dec2OctTest.php | 5 +- .../Functions/Engineering/DeltaTest.php | 2 +- .../Functions/Engineering/ErfCTest.php | 2 +- .../Functions/Engineering/ErfPreciseTest.php | 2 +- .../Functions/Engineering/ErfTest.php | 2 +- .../Functions/Engineering/GeStepTest.php | 2 +- .../Functions/Engineering/Hex2BinTest.php | 5 +- .../Functions/Engineering/Hex2DecTest.php | 5 +- .../Functions/Engineering/Hex2OctTest.php | 5 +- .../Functions/Engineering/ImAbsTest.php | 2 +- .../Functions/Engineering/ImArgumentTest.php | 2 +- .../Functions/Engineering/ImConjugateTest.php | 4 +- .../Functions/Engineering/ImCosTest.php | 4 +- .../Functions/Engineering/ImCoshTest.php | 4 +- .../Functions/Engineering/ImCotTest.php | 4 +- .../Functions/Engineering/ImCscTest.php | 4 +- .../Functions/Engineering/ImCschTest.php | 4 +- .../Functions/Engineering/ImDivTest.php | 4 +- .../Functions/Engineering/ImExpTest.php | 4 +- .../Functions/Engineering/ImLnTest.php | 4 +- .../Functions/Engineering/ImLog10Test.php | 4 +- .../Functions/Engineering/ImLog2Test.php | 4 +- .../Functions/Engineering/ImPowerTest.php | 4 +- .../Functions/Engineering/ImProductTest.php | 4 +- .../Functions/Engineering/ImRealTest.php | 2 +- .../Functions/Engineering/ImSecTest.php | 4 +- .../Functions/Engineering/ImSechTest.php | 4 +- .../Functions/Engineering/ImSinTest.php | 4 +- .../Functions/Engineering/ImSinhTest.php | 4 +- .../Functions/Engineering/ImSqrtTest.php | 4 +- .../Functions/Engineering/ImSubTest.php | 4 +- .../Functions/Engineering/ImSumTest.php | 4 +- .../Functions/Engineering/ImTanTest.php | 4 +- .../Functions/Engineering/ImaginaryTest.php | 2 +- .../Functions/Engineering/Oct2BinTest.php | 5 +- .../Functions/Engineering/Oct2DecTest.php | 5 +- .../Functions/Engineering/Oct2HexTest.php | 5 +- .../Functions/Financial/AccrintMTest.php | 2 +- .../Functions/Financial/AccrintTest.php | 2 +- .../Functions/Financial/AmorDegRcTest.php | 2 +- .../Functions/Financial/AmorLincTest.php | 2 +- .../Functions/Financial/CoupDayBsTest.php | 2 +- .../Functions/Financial/CoupDaysNcTest.php | 2 +- .../Functions/Financial/CoupDaysTest.php | 2 +- .../Functions/Financial/CoupNcdTest.php | 2 +- .../Functions/Financial/CoupNumTest.php | 2 +- .../Functions/Financial/CoupPcdTest.php | 2 +- .../Functions/Financial/CumIpmtTest.php | 2 +- .../Functions/Financial/CumPrincTest.php | 2 +- .../Functions/Financial/DbTest.php | 2 +- .../Functions/Financial/DdbTest.php | 2 +- .../Functions/Financial/DiscTest.php | 2 +- .../Functions/Financial/DollarDeTest.php | 2 +- .../Functions/Financial/DollarFrTest.php | 2 +- .../Functions/Financial/EffectTest.php | 2 +- .../Functions/Financial/FvScheduleTest.php | 2 +- .../Functions/Financial/FvTest.php | 2 +- .../Functions/Financial/HelpersTest.php | 4 +- .../Functions/Financial/IPmtTest.php | 2 +- .../Functions/Financial/IntRateTest.php | 2 +- .../Functions/Financial/IrrTest.php | 2 +- .../Functions/Financial/IsPmtTest.php | 2 +- .../Functions/Financial/MirrTest.php | 2 +- .../Functions/Financial/NPerTest.php | 2 +- .../Functions/Financial/NominalTest.php | 2 +- .../Functions/Financial/NpvTest.php | 2 +- .../Functions/Financial/PDurationTest.php | 2 +- .../Functions/Financial/PmtTest.php | 2 +- .../Functions/Financial/PpmtTest.php | 2 +- .../Functions/Financial/PriceDiscTest.php | 2 +- .../Functions/Financial/PriceMatTest.php | 2 +- .../Functions/Financial/PriceTest.php | 4 +- .../Functions/Financial/PvTest.php | 2 +- .../Functions/Financial/RateTest.php | 2 +- .../Functions/Financial/ReceivedTest.php | 2 +- .../Functions/Financial/RriTest.php | 2 +- .../Functions/Financial/SlnTest.php | 2 +- .../Functions/Financial/SydTest.php | 2 +- .../Functions/Financial/TBillEqTest.php | 2 +- .../Functions/Financial/TBillPriceTest.php | 2 +- .../Functions/Financial/TBillYieldTest.php | 2 +- .../Functions/Financial/XNpvTest.php | 2 +- .../Functions/Financial/XirrTest.php | 2 +- .../Functions/Financial/YieldDiscTest.php | 2 +- .../Functions/Financial/YieldMatTest.php | 2 +- .../Calculation/Functions/Logical/AndTest.php | 2 +- .../Functions/Logical/IfErrorTest.php | 2 +- .../Functions/Logical/IfNaTest.php | 2 +- .../Calculation/Functions/Logical/IfTest.php | 2 +- .../Calculation/Functions/Logical/IfsTest.php | 2 +- .../Calculation/Functions/Logical/NotTest.php | 2 +- .../Calculation/Functions/Logical/OrTest.php | 2 +- .../Functions/Logical/SwitchTest.php | 2 +- .../Calculation/Functions/Logical/XorTest.php | 2 +- .../Functions/LookupRef/AddressTest.php | 2 +- .../Functions/LookupRef/ChooseTest.php | 2 +- .../Functions/LookupRef/ColumnTest.php | 2 +- .../Functions/LookupRef/ColumnsTest.php | 2 +- .../Functions/LookupRef/HLookupTest.php | 2 +- .../Functions/LookupRef/IndexTest.php | 2 +- .../Functions/LookupRef/IndirectTest.php | 2 +- .../Functions/LookupRef/LookupTest.php | 2 +- .../Functions/LookupRef/MatchTest.php | 2 +- .../Functions/LookupRef/OffsetTest.php | 2 +- .../Functions/LookupRef/RowTest.php | 2 +- .../Functions/LookupRef/RowsTest.php | 2 +- .../Functions/LookupRef/TransposeTest.php | 2 +- .../Functions/LookupRef/VLookupTest.php | 2 +- .../Functions/MathTrig/AbsTest.php | 2 +- .../Functions/MathTrig/AcosTest.php | 2 +- .../Functions/MathTrig/AcoshTest.php | 2 +- .../Functions/MathTrig/AcotTest.php | 2 +- .../Functions/MathTrig/AcothTest.php | 2 +- .../Functions/MathTrig/AllSetupTeardown.php | 16 +- .../Functions/MathTrig/ArabicTest.php | 2 +- .../Functions/MathTrig/AsinTest.php | 2 +- .../Functions/MathTrig/AsinhTest.php | 2 +- .../Functions/MathTrig/Atan2Test.php | 2 +- .../Functions/MathTrig/AtanTest.php | 2 +- .../Functions/MathTrig/AtanhTest.php | 2 +- .../Functions/MathTrig/BaseTest.php | 2 +- .../Functions/MathTrig/CeilingMathTest.php | 2 +- .../Functions/MathTrig/CeilingPreciseTest.php | 2 +- .../Functions/MathTrig/CeilingTest.php | 2 +- .../Functions/MathTrig/CombinATest.php | 2 +- .../Functions/MathTrig/CombinTest.php | 2 +- .../Functions/MathTrig/CosTest.php | 2 +- .../Functions/MathTrig/CoshTest.php | 2 +- .../Functions/MathTrig/CotTest.php | 2 +- .../Functions/MathTrig/CothTest.php | 2 +- .../Functions/MathTrig/CscTest.php | 2 +- .../Functions/MathTrig/CschTest.php | 2 +- .../Functions/MathTrig/DegreesTest.php | 2 +- .../Functions/MathTrig/EvenTest.php | 2 +- .../Functions/MathTrig/ExpTest.php | 2 +- .../Functions/MathTrig/FactDoubleTest.php | 2 +- .../Functions/MathTrig/FactTest.php | 4 +- .../Functions/MathTrig/FloorMathTest.php | 2 +- .../Functions/MathTrig/FloorPreciseTest.php | 2 +- .../Functions/MathTrig/FloorTest.php | 2 +- .../Functions/MathTrig/GcdTest.php | 2 +- .../Functions/MathTrig/IntTest.php | 2 +- .../Functions/MathTrig/LcmTest.php | 2 +- .../Calculation/Functions/MathTrig/LnTest.php | 2 +- .../Functions/MathTrig/Log10Test.php | 2 +- .../Functions/MathTrig/LogTest.php | 2 +- .../Functions/MathTrig/MInverseTest.php | 2 +- .../Functions/MathTrig/MMultTest.php | 2 +- .../Functions/MathTrig/MRoundTest.php | 2 +- .../Functions/MathTrig/MdeTermTest.php | 2 +- .../Functions/MathTrig/ModTest.php | 2 +- .../Functions/MathTrig/MultinomialTest.php | 2 +- .../Functions/MathTrig/OddTest.php | 2 +- .../Functions/MathTrig/PowerTest.php | 2 +- .../Functions/MathTrig/ProductTest.php | 2 +- .../Functions/MathTrig/QuotientTest.php | 2 +- .../Functions/MathTrig/RadiansTest.php | 2 +- .../Functions/MathTrig/RandBetweenTest.php | 2 +- .../Functions/MathTrig/RomanTest.php | 2 +- .../Functions/MathTrig/RoundDownTest.php | 2 +- .../Functions/MathTrig/RoundTest.php | 2 +- .../Functions/MathTrig/RoundUpTest.php | 2 +- .../Functions/MathTrig/SecTest.php | 2 +- .../Functions/MathTrig/SechTest.php | 2 +- .../Functions/MathTrig/SeriesSumTest.php | 2 +- .../Functions/MathTrig/SignTest.php | 2 +- .../Functions/MathTrig/SinTest.php | 2 +- .../Functions/MathTrig/SinhTest.php | 2 +- .../Functions/MathTrig/SqrtPiTest.php | 2 +- .../Functions/MathTrig/SqrtTest.php | 2 +- .../Functions/MathTrig/SubTotalTest.php | 4 +- .../Functions/MathTrig/SumIfTest.php | 2 +- .../Functions/MathTrig/SumIfsTest.php | 2 +- .../Functions/MathTrig/SumProductTest.php | 2 +- .../Functions/MathTrig/SumSqTest.php | 2 +- .../Functions/MathTrig/SumTest.php | 2 +- .../Functions/MathTrig/SumX2MY2Test.php | 2 +- .../Functions/MathTrig/SumX2PY2Test.php | 2 +- .../Functions/MathTrig/SumXMY2Test.php | 2 +- .../Functions/MathTrig/TanTest.php | 2 +- .../Functions/MathTrig/TanhTest.php | 2 +- .../Functions/MathTrig/TruncTest.php | 2 +- .../Functions/Statistical/AveDevTest.php | 2 +- .../Functions/Statistical/AverageATest.php | 2 +- .../Functions/Statistical/AverageIfTest.php | 2 +- .../Functions/Statistical/AverageIfsTest.php | 2 +- .../Functions/Statistical/AverageTest.php | 2 +- .../Functions/Statistical/BetaDistTest.php | 2 +- .../Functions/Statistical/BetaInvTest.php | 2 +- .../Statistical/BinomDistRangeTest.php | 2 +- .../Functions/Statistical/BinomDistTest.php | 2 +- .../Functions/Statistical/BinomInvTest.php | 2 +- .../Statistical/ChiDistLeftTailTest.php | 2 +- .../Statistical/ChiDistRightTailTest.php | 2 +- .../Statistical/ChiInvLeftTailTest.php | 2 +- .../Statistical/ChiInvRightTailTest.php | 2 +- .../Functions/Statistical/ChiTestTest.php | 2 +- .../Functions/Statistical/ConfidenceTest.php | 2 +- .../Functions/Statistical/CorrelTest.php | 2 +- .../Functions/Statistical/CountATest.php | 2 +- .../Functions/Statistical/CountBlankTest.php | 2 +- .../Functions/Statistical/CountIfTest.php | 2 +- .../Functions/Statistical/CountIfsTest.php | 2 +- .../Functions/Statistical/CountTest.php | 11 +- .../Functions/Statistical/CovarTest.php | 2 +- .../Functions/Statistical/ExponDistTest.php | 2 +- .../Functions/Statistical/FisherInvTest.php | 2 +- .../Functions/Statistical/FisherTest.php | 2 +- .../Functions/Statistical/ForecastTest.php | 2 +- .../Functions/Statistical/GammaDistTest.php | 2 +- .../Functions/Statistical/GammaInvTest.php | 2 +- .../Functions/Statistical/GammaLnTest.php | 2 +- .../Functions/Statistical/GeoMeanTest.php | 2 +- .../Functions/Statistical/GrowthTest.php | 2 +- .../Functions/Statistical/HarMeanTest.php | 2 +- .../Functions/Statistical/HypGeomDistTest.php | 2 +- .../Functions/Statistical/InterceptTest.php | 2 +- .../Functions/Statistical/KurtTest.php | 6 +- .../Functions/Statistical/LargeTest.php | 2 +- .../Functions/Statistical/LinEstTest.php | 6 +- .../Functions/Statistical/LogEstTest.php | 8 +- .../Functions/Statistical/MaxIfsTest.php | 2 +- .../Functions/Statistical/MedianTest.php | 2 +- .../Functions/Statistical/MinIfsTest.php | 2 +- .../Statistical/NegBinomDistTest.php | 2 +- .../Functions/Statistical/NormInvTest.php | 2 +- .../Functions/Statistical/PercentRankTest.php | 2 +- .../Functions/Statistical/PercentileTest.php | 2 +- .../Functions/Statistical/PermutTest.php | 2 +- .../Statistical/PermutationATest.php | 2 +- .../Functions/Statistical/PoissonTest.php | 2 +- .../Functions/Statistical/QuartileTest.php | 2 +- .../Functions/Statistical/RankTest.php | 2 +- .../Functions/Statistical/RsqTest.php | 2 +- .../Functions/Statistical/SkewTest.php | 2 +- .../Functions/Statistical/SlopeTest.php | 2 +- .../Functions/Statistical/SmallTest.php | 2 +- .../Functions/Statistical/StDevATest.php | 4 +- .../Functions/Statistical/StDevPATest.php | 4 +- .../Functions/Statistical/StDevPTest.php | 4 +- .../Functions/Statistical/StDevTest.php | 4 +- .../Functions/Statistical/SteyxTest.php | 2 +- .../Functions/Statistical/TDistTest.php | 2 +- .../Functions/Statistical/TinvTest.php | 2 +- .../Functions/Statistical/TrendTest.php | 2 +- .../Functions/Statistical/TrimMeanTest.php | 2 +- .../Functions/Statistical/VarATest.php | 4 +- .../Functions/Statistical/VarPATest.php | 4 +- .../Functions/Statistical/VarPTest.php | 4 +- .../Functions/Statistical/VarTest.php | 4 +- .../Functions/Statistical/WeibullTest.php | 2 +- .../Functions/Statistical/ZTestTest.php | 2 +- .../Functions/TextData/CharTest.php | 2 +- .../Functions/TextData/CleanTest.php | 2 +- .../Functions/TextData/CodeTest.php | 2 +- .../Functions/TextData/ConcatenateTest.php | 2 +- .../Functions/TextData/DollarTest.php | 2 +- .../Functions/TextData/ExactTest.php | 5 +- .../Functions/TextData/FindTest.php | 2 +- .../Functions/TextData/FixedTest.php | 2 +- .../Functions/TextData/LeftTest.php | 4 +- .../Functions/TextData/LenTest.php | 2 +- .../Functions/TextData/LowerTest.php | 4 +- .../Functions/TextData/MidTest.php | 4 +- .../Functions/TextData/NumberValueTest.php | 2 +- .../Functions/TextData/ProperTest.php | 4 +- .../Functions/TextData/ReplaceTest.php | 2 +- .../Functions/TextData/ReptTest.php | 2 +- .../Functions/TextData/RightTest.php | 4 +- .../Functions/TextData/SearchTest.php | 2 +- .../Functions/TextData/SubstituteTest.php | 2 +- .../Calculation/Functions/TextData/TTest.php | 2 +- .../Functions/TextData/TextJoinTest.php | 2 +- .../Functions/TextData/TextTest.php | 2 +- .../Functions/TextData/TrimTest.php | 2 +- .../Functions/TextData/UpperTest.php | 4 +- .../Functions/TextData/ValueTest.php | 11 +- .../Calculation/FunctionsTest.php | 36 +- .../Calculation/LookupRefTest.php | 2 +- .../Calculation/TranslationTest.php | 8 +- .../Calculation/XlfnFunctionsTest.php | 2 +- .../Cell/AddressHelperTest.php | 12 +- .../Cell/AdvancedValueBinderTest.php | 29 +- tests/PhpSpreadsheetTests/Cell/CellTest.php | 4 +- .../Cell/CoordinateTest.php | 29 +- .../PhpSpreadsheetTests/Cell/DataTypeTest.php | 1 + .../Cell/DefaultValueBinderTest.php | 6 +- .../Cell/HyperlinkTest.php | 4 +- ...ueBinderWithOverriddenDataTypeForValue.php | 3 + .../PhpSpreadsheetTests/Chart/LegendTest.php | 15 +- .../Custom/ComplexAssert.php | 29 +- .../DefinedNameFormulaTest.php | 10 +- tests/PhpSpreadsheetTests/DefinedNameTest.php | 50 +- .../Document/PropertiesTest.php | 5 +- .../Functional/AbstractFunctional.php | 2 +- .../Functional/ActiveSheetTest.php | 2 +- .../Functional/ColumnWidthTest.php | 2 +- .../Functional/CommentsTest.php | 2 +- .../Functional/ConditionalStopIfTrueTest.php | 2 +- .../Functional/EnclosureTest.php | 2 +- .../Functional/FreezePaneTest.php | 2 +- .../Functional/MergedCellsTest.php | 2 +- .../Functional/PrintAreaTest.php | 2 +- .../Functional/ReadBlankCellsTest.php | 2 +- .../Functional/ReadFilterTest.php | 2 +- .../Functional/SelectedCellsTest.php | 2 +- .../TypeAttributePreservationTest.php | 2 +- .../Functional/WorkbookViewAttributesTest.php | 2 +- tests/PhpSpreadsheetTests/Helper/HtmlTest.php | 2 +- .../PhpSpreadsheetTests/Helper/SampleTest.php | 2 +- tests/PhpSpreadsheetTests/IOFactoryTest.php | 6 +- .../Reader/CsvContiguousFilter.php | 9 + .../Reader/CsvContiguousTest.php | 3 + tests/PhpSpreadsheetTests/Reader/CsvTest.php | 10 +- .../Reader/Html/HtmlHelper.php | 3 +- .../Reader/Html/HtmlTest.php | 10 +- .../Reader/Ods/OdsTest.php | 7 +- .../Reader/Security/XmlScannerTest.php | 6 +- tests/PhpSpreadsheetTests/Reader/SlkTest.php | 6 + .../Reader/Xlsx/AutoFilterTest.php | 2 +- .../ConditionalFormattingDataBarXlsxTest.php | 4 +- .../PhpSpreadsheetTests/Reader/Xlsx2Test.php | 4 +- tests/PhpSpreadsheetTests/Reader/XlsxTest.php | 4 +- .../Reader/Xml/XmlOddTest.php | 5 +- .../Reader/Xml/XmlTest.php | 2 +- tests/PhpSpreadsheetTests/SettingsTest.php | 2 +- .../Shared/CodePageTest.php | 2 +- tests/PhpSpreadsheetTests/Shared/DateTest.php | 23 +- tests/PhpSpreadsheetTests/Shared/FontTest.php | 6 +- .../Shared/PasswordHasherTest.php | 2 +- .../Shared/StringHelperTest.php | 9 + .../Shared/TimeZoneTest.php | 7 + .../Shared/Trend/ExponentialBestFitTest.php | 2 +- .../Shared/Trend/LinearBestFitTest.php | 2 +- tests/PhpSpreadsheetTests/SpreadsheetTest.php | 5 +- tests/PhpSpreadsheetTests/Style/ColorTest.php | 8 +- .../Style/NumberFormatTest.php | 13 +- .../Worksheet/AutoFilter/Column/RuleTest.php | 32 +- .../Worksheet/AutoFilter/ColumnTest.php | 39 +- .../Worksheet/AutoFilterTest.php | 10 + .../Worksheet/ColumnCellIteratorTest.php | 11 +- .../Worksheet/ColumnDimensionTest.php | 2 +- .../Worksheet/ColumnIteratorTest.php | 12 +- .../Worksheet/ColumnTest.php | 8 +- .../Worksheet/RowCellIteratorTest.php | 11 +- .../Worksheet/RowIteratorTest.php | 12 +- .../PhpSpreadsheetTests/Worksheet/RowTest.php | 8 +- .../Worksheet/WorksheetNamedRangesTest.php | 6 +- .../Worksheet/WorksheetTest.php | 8 +- .../Writer/Csv/CsvEnclosureTest.php | 12 +- .../Writer/Csv/CsvOutputEncodingTest.php | 2 +- .../Writer/Csv/CsvWriteTest.php | 2 +- .../Writer/Html/CallbackTest.php | 2 +- .../Writer/Html/HtmlCommentsTest.php | 5 +- .../Writer/Html/HtmlNumberFormatTest.php | 13 +- .../Writer/Html/ImagesRootTest.php | 3 + .../Writer/Html/XssVulnerabilityTest.php | 8 +- .../Writer/Ods/ContentTest.php | 7 + .../Writer/RetainSelectedCellsTest.php | 2 +- .../Writer/Xls/FormulaErrTest.php | 2 +- .../Writer/Xls/WorkbookTest.php | 2 +- .../Writer/Xls/XlsGifBmpTest.php | 3 + .../Writer/Xlsx/DrawingsTest.php | 2 +- .../Writer/Xlsx/FloatsRetainedTest.php | 4 +- .../Writer/Xlsx/LocaleFloatsTest.php | 10 +- .../Writer/Xlsx/StartsWithHashTest.php | 4 +- .../Writer/Xlsx/UnparsedDataCloneTest.php | 6 +- .../Writer/Xlsx/UnparsedDataTest.php | 2 +- tests/data/Calculation/Calculation.php | 2 +- tests/data/Calculation/Logical/XOR.php | 12 +- 433 files changed, 1596 insertions(+), 7199 deletions(-) diff --git a/composer.json b/composer.json index d0c3a16d..6cd65021 100644 --- a/composer.json +++ b/composer.json @@ -81,6 +81,7 @@ "mpdf/mpdf": "^8.0", "phpcompatibility/php-compatibility": "^9.3", "phpstan/phpstan": "^0.12.82", + "phpstan/phpstan-phpunit": "^0.12.18", "phpunit/phpunit": "^8.5", "squizlabs/php_codesniffer": "^3.5", "tecnickcom/tcpdf": "^6.3" diff --git a/composer.lock b/composer.lock index e4060972..3670f857 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "89b62d75519340c289a3a763245f1ca0", + "content-hash": "3be2673a6367d296c616bf9c34b77953", "packages": [ { "name": "ezyang/htmlpurifier", @@ -2023,6 +2023,61 @@ ], "time": "2021-03-19T06:08:17+00:00" }, + { + "name": "phpstan/phpstan-phpunit", + "version": "0.12.18", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-phpunit.git", + "reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72", + "reference": "ab44aec7cfb5cb267b8bc30a8caea86dd50d1f72", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "phpstan/phpstan": "^0.12.60" + }, + "conflict": { + "phpunit/phpunit": "<7.0" + }, + "require-dev": { + "phing/phing": "^2.16.3", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-strict-rules": "^0.12.6", + "phpunit/phpunit": "^7.5.20" + }, + "type": "phpstan-extension", + "extra": { + "branch-alias": { + "dev-master": "0.12-dev" + }, + "phpstan": { + "includes": [ + "extension.neon", + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPUnit extensions and rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-phpunit/issues", + "source": "https://github.com/phpstan/phpstan-phpunit/tree/0.12.18" + }, + "time": "2021-03-06T11:51:27+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "7.0.14", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index c80e5931..494b90a8 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -5,26 +5,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$calculationCache type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$branchPruningEnabled has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$operators type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$binaryOperators type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$cellStack has no typehint specified\\.$#" count: 1 @@ -135,21 +120,6 @@ parameters: count: 6 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:parseFormula\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:checkMatrixOperands\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getMatrixDimensions\\(\\) has parameter \\$matrix with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:\\$operatorAssociativity has no typehint specified\\.$#" count: 1 @@ -245,11 +215,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:executeArrayComparison\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:strCaseReverse\\(\\) expects string, string\\|null given\\.$#" count: 2 @@ -290,31 +255,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getFunctions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getImplementedFunctionNames\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:addCellReference\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:addCellReference\\(\\) has parameter \\$functionCall with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:addCellReference\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Calculation\\:\\:getUnusedBranchStoreKey\\(\\) has no return typehint specified\\.$#" count: 1 @@ -395,71 +335,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:getFilteredColumn\\(\\) has parameter \\$criteria with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:getFilteredColumn\\(\\) has parameter \\$database with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:getFilteredColumn\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:buildQuery\\(\\) has parameter \\$criteria with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:buildQuery\\(\\) has parameter \\$criteriaNames with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:buildCondition\\(\\) has parameter \\$criterion with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) has parameter \\$criteria with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) has parameter \\$database with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) has parameter \\$fields with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:executeQuery\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:processCondition\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:processCondition\\(\\) has parameter \\$dataValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Database\\\\DatabaseAbstract\\:\\:processCondition\\(\\) has parameter \\$fields with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Database/DatabaseAbstract.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTime\\:\\:NETWORKDAYS\\(\\) has parameter \\$dateArgs with no typehint specified\\.$#" count: 1 @@ -485,16 +370,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:t1ToString\\(\\) has parameter \\$t1 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:setUpArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php - - message: "#^Parameter \\#1 \\$testVal1 of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:adjustYear\\(\\) expects string, string\\|false given\\.$#" count: 1 @@ -505,11 +380,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\DateValue\\:\\:finalResults\\(\\) has parameter \\$PHPDateArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/DateValue.php - - message: "#^Parameter \\#1 \\$value of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:testStringAsNumeric\\(\\) expects string, float\\|int\\|string given\\.$#" count: 2 @@ -535,11 +405,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\Helpers\\:\\:returnIn3FormatsArray\\(\\) has parameter \\$dateArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php - - message: "#^Parameter \\#1 \\$excelTimestamp of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:excelToTimestamp\\(\\) expects float\\|int, bool\\|float given\\.$#" count: 1 @@ -590,11 +455,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:incrementing\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - message: "#^Binary operation \"\\-\" between 7 and int\\|string results in an error\\.$#" count: 1 @@ -605,26 +465,11 @@ parameters: count: 2 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:incrementingArray\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:decrementing\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - message: "#^Binary operation \"\\-\" between 4 and int\\<5, max\\>\\|string results in an error\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WorkDay\\:\\:decrementingArray\\(\\) has parameter \\$holidayArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/DateTimeExcel/WorkDay.php - - message: "#^Binary operation \"\\-\" between int\\|string and int\\|string results in an error\\.$#" count: 1 @@ -650,21 +495,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Engineering.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:getConversionGroups\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:getConversionGroupUnits\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\:\\:getConversionGroupUnitDetails\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselI\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" count: 1 @@ -770,11 +600,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BitWise\\:\\:splitNumber\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BitWise.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BitWise\\:\\:validateBitwiseArgument\\(\\) never returns int so it can be removed from the return typehint\\.$#" count: 1 @@ -805,21 +630,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Engineering/ConvertBase.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getConversionCategories\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getConversionCategoryUnits\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getConversionCategoryUnitDetails\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/ConvertUOM.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\ConvertUOM\\:\\:getUOMDetails\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2005,11 +1815,6 @@ parameters: count: 4 path: src/PhpSpreadsheet/Calculation/FormulaParser.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:\\$errorCodes type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Functions.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:isMatrixValue\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2060,16 +1865,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Functions.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:flattenArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Functions.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Functions\\:\\:flattenArrayIndexed\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Functions.php - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 1 @@ -2085,11 +1880,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\MakeMatrix\\:\\:make\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Internal/MakeMatrix.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\WildcardMatch\\:\\:wildcard\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -2110,46 +1900,6 @@ parameters: count: 3 path: src/PhpSpreadsheet/Calculation/Logical/Operations.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Logical\\\\Operations\\:\\:countTrueValues\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Logical/Operations.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:COLUMN\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:COLUMNS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:ROW\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:ROWS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:INDIRECT\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:INDIRECT\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:OFFSET\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:OFFSET\\(\\) should return array\\|string but returns array\\|int\\|string\\.$#" count: 1 @@ -2165,16 +1915,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:TRANSPOSE\\(\\) has parameter \\$matrixData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\:\\:TRANSPOSE\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 2 @@ -2310,16 +2050,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/HLookup.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:INDIRECT\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:INDIRECT\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:extractRequiredCells\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2330,51 +2060,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Indirect\\:\\:extractWorksheet\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Indirect.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyLookupValues\\(\\) has parameter \\$lookupVector with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyLookupValues\\(\\) has parameter \\$resultVector with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyLookupValues\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has parameter \\$lookupVector with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:verifyResultVector\\(\\) has parameter \\$resultVector with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:rowCount\\(\\) has parameter \\$dataArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Lookup\\:\\:columnCount\\(\\) has parameter \\$dataArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Lookup.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\LookupBase\\:\\:validateIndexLookup\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2395,11 +2090,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/LookupBase.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:transpose\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php - - message: "#^Parameter \\#3 \\$rowNum of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) expects int, float\\|int\\<0, max\\>\\|string given\\.$#" count: 1 @@ -2410,21 +2100,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) has parameter \\$matrix with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Matrix\\:\\:extractRowValue\\(\\) has parameter \\$rowKeys with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Matrix.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:OFFSET\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:extractRequiredCells\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2435,11 +2110,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:extractWorksheet\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Offset\\:\\:adjustEndCellColumnForWidth\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2470,11 +2140,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/Offset.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:COLUMN\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php - - message: "#^Parameter \\#1 \\$pString of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:columnIndexFromString\\(\\) expects string, string\\|null given\\.$#" count: 3 @@ -2485,16 +2150,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:COLUMNS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:ROW\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php - - message: "#^Parameter \\#1 \\$low of function range expects float\\|int\\|string, string\\|null given\\.$#" count: 1 @@ -2505,11 +2160,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\RowColumnInformation\\:\\:ROWS\\(\\) has parameter \\$cellAddress with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef/RowColumnInformation.php - - message: "#^Parameter \\#2 \\$cmp_function of function uasort expects callable\\(mixed, mixed\\)\\: int, array\\('self', 'vlookupSort'\\) given\\.$#" count: 1 @@ -2575,36 +2225,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MDETERM\\(\\) has parameter \\$matrixValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MINVERSE\\(\\) has parameter \\$matrixValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MINVERSE\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MMULT\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MMULT\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MMULT\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\:\\:MOD\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" count: 1 @@ -2620,16 +2240,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/MathTrig.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Arabic\\:\\:calculateArabic\\(\\) has parameter \\$roman with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Arabic\\:\\:strSplit\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/Arabic.php - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" count: 1 @@ -2660,31 +2270,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Lcm\\:\\:processPoweredFactors\\(\\) has parameter \\$allPoweredFactors with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Lcm\\:\\:processPoweredFactors\\(\\) has parameter \\$myPoweredFactors with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/Lcm.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\MatrixFunctions\\:\\:funcMInverse\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\MatrixFunctions\\:\\:funcMMult\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\MatrixFunctions\\:\\:funcMUnit\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\Roman\\:\\:romanCut\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2745,16 +2330,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\SumSquares\\:\\:getCount\\(\\) has parameter \\$array1 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\MathTrig\\\\SumSquares\\:\\:getCount\\(\\) has parameter \\$array2 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/MathTrig/SumSquares.php - - message: "#^Parameter \\#1 \\$str of function rtrim expects string, int given\\.$#" count: 1 @@ -2765,21 +2340,6 @@ parameters: count: 4 path: src/PhpSpreadsheet/Calculation/Statistical.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:KURT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:LINEST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:LOGEST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:MAXIFS\\(\\) should return float but returns float\\|string\\|null\\.$#" count: 1 @@ -2790,11 +2350,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\:\\:SKEW\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Averages\\:\\:filterArguments\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2850,21 +2405,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:percentileFilterValues\\(\\) has parameter \\$dataSet with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:rankFilterValues\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:rankFilterValues\\(\\) has parameter \\$dataSet with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Permutations\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" count: 1 @@ -2895,16 +2440,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:filterTrendValues\\(\\) has parameter \\$array1 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:filterTrendValues\\(\\) has parameter \\$array2 with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:checkTrendArrays\\(\\) has parameter \\$array1 with no typehint specified\\.$#" count: 1 @@ -2915,31 +2450,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateTrendArrays\\(\\) has parameter \\$xValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateTrendArrays\\(\\) has parameter \\$yValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:GROWTH\\(\\) should return array\\ but returns array\\\\>\\>\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:LINEST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:LOGEST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:TREND\\(\\) should return array\\ but returns array\\\\>\\>\\.$#" count: 1 @@ -2955,81 +2470,31 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSet\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSetForValueRange\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditionSetForValueRange\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditions\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildConditions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabase\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabase\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabaseWithValueRange\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDatabaseWithValueRange\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) has parameter \\$database with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:buildDataSet\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:databaseFromRangeAndValue\\(\\) has parameter \\$range with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:databaseFromRangeAndValue\\(\\) has parameter \\$valueRange with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Conditional\\:\\:databaseFromRangeAndValue\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" count: 1 @@ -3810,16 +3275,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Token/Stack.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\AdvancedValueBinder\\:\\:setImproperFraction\\(\\) has parameter \\$matches with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/AdvancedValueBinder.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\AdvancedValueBinder\\:\\:setProperFraction\\(\\) has parameter \\$matches with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/AdvancedValueBinder.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\:\\:\\$formulaAttributes has no typehint specified\\.$#" count: 1 @@ -3845,71 +3300,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Cell/Cell.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:splitRange\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - message: "#^Parameter \\#2 \\$str of function explode expects string, array\\\\|string given\\.$#" count: 1 path: src/PhpSpreadsheet/Cell/Coordinate.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:buildRange\\(\\) has parameter \\$pRange with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:rangeBoundaries\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:rangeDimension\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:getRangeBoundaries\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:extractAllCellReferencesInRange\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:processRangeSetOperators\\(\\) has parameter \\$cells with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:processRangeSetOperators\\(\\) has parameter \\$operators with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:processRangeSetOperators\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:sortCellReferenceArray\\(\\) has parameter \\$cellList with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:sortCellReferenceArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:getReferencesForCellBlock\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - message: "#^Parameter \\#4 \\$currentRow of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:validateRange\\(\\) expects int, string given\\.$#" count: 1 @@ -3920,16 +3315,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Cell/Coordinate.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:mergeRangesInCollection\\(\\) has parameter \\$pCoordCollection with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:mergeRangesInCollection\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/Coordinate.php - - message: "#^Call to an undefined method object\\:\\:getHashCode\\(\\)\\.$#" count: 1 @@ -3940,26 +3325,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Cell/Coordinate.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataType\\:\\:\\$errorCodes type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/DataType.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataType\\:\\:getErrorCodes\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Cell/DataType.php - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:substring\\(\\) expects string, string\\|null given\\.$#" count: 1 path: src/PhpSpreadsheet/Cell/DataType.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:getLineStyleProperty\\(\\) has parameter \\$elements with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Axis.php - - message: "#^Parameter \\#2 \\$alpha of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowColor\\(\\) expects int, int\\|string given\\.$#" count: 1 @@ -3980,21 +3350,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/Axis.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:setShadowProperiesMapValues\\(\\) has parameter \\$properties_map with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Axis.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:getShadowProperty\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Axis.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\:\\:getGlowProperty\\(\\) has parameter \\$property with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Axis.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$title \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" count: 1 @@ -4075,11 +3430,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/Chart.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:getBottomRightPosition\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:setBottomRightCell\\(\\) has no return typehint specified\\.$#" count: 1 @@ -4140,11 +3490,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/DataSeriesValues.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:setDataValues\\(\\) has parameter \\$dataValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/DataSeriesValues.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\:\\:refresh\\(\\) has parameter \\$flatten with no typehint specified\\.$#" count: 1 @@ -4175,11 +3520,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/GridLines.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:getLineStyleProperty\\(\\) has parameter \\$elements with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/GridLines.php - - message: "#^Parameter \\#1 \\$color of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setGlowColor\\(\\) expects string, string\\|null given\\.$#" count: 1 @@ -4210,16 +3550,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/GridLines.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\:\\:setShadowProperiesMapValues\\(\\) has parameter \\$properties_map with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/GridLines.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\:\\:__construct\\(\\) has parameter \\$layout with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Layout.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:\\$positionXLref has no typehint specified\\.$#" count: 1 @@ -4595,11 +3925,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Collection/Cells.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getHighestRowAndColumn\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Cells.php - - message: "#^Parameter \\#1 \\$string of function substr expects string, string\\|false given\\.$#" count: 1 @@ -4635,26 +3960,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Collection/Memory.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:deleteMultiple\\(\\) has parameter \\$keys with no value type specified in iterable type iterable\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Memory.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:getMultiple\\(\\) has parameter \\$keys with no value type specified in iterable type iterable\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Memory.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:getMultiple\\(\\) return type has no value type specified in iterable type iterable\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Memory.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:setMultiple\\(\\) has parameter \\$values with no value type specified in iterable type iterable\\.$#" - count: 1 - path: src/PhpSpreadsheet/Collection/Memory.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 2 @@ -4700,21 +4005,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Document/Properties.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:getCategories\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/DocumentGenerator.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:tableRow\\(\\) has parameter \\$lengths with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/DocumentGenerator.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:tableRow\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/DocumentGenerator.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\DocumentGenerator\\:\\:getPhpSpreadsheetFunctionText\\(\\) has parameter \\$functionCall with no typehint specified\\.$#" count: 1 @@ -4865,11 +4155,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Helper/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\:\\:handleCallback\\(\\) has parameter \\$callbacks with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Helper/Html.php - - message: "#^Parameter \\#1 \\$function of function call_user_func expects callable\\(\\)\\: mixed, array\\(\\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Helper\\\\Html\\), mixed\\) given\\.$#" count: 1 @@ -4920,11 +4205,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/IOFactory.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\NamedRange\\:\\:getCellsInRange\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/NamedRange.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\BaseReader\\:\\:\\$fileHandle has no typehint specified\\.$#" count: 1 @@ -4940,11 +4220,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Csv.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Csv.php - - message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, array\\|null given\\.$#" count: 1 @@ -5030,11 +4305,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\\\Delimiter\\:\\:countDelimiterValues\\(\\) has parameter \\$delimiterKeys with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|null given\\.$#" count: 1 @@ -5045,11 +4315,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Csv/Delimiter.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:\\$expressions type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:\\$referenceHelper has no typehint specified\\.$#" count: 1 @@ -5065,26 +4330,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:\\$mappings has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:gnumericMappings\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCreated\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" count: 2 @@ -5095,31 +4345,11 @@ parameters: count: 2 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:docPropertiesMeta\\(\\) has parameter \\$namespacesMeta with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:docProperties\\(\\) has parameter \\$namespacesMeta with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addBorderDiagonal\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addBorderStyle\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Offset 'No' does not exist on SimpleXMLElement\\|null\\.$#" count: 2 @@ -5155,16 +4385,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addStyle\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addStyle2\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:parseBorderAttributes\\(\\) has no return typehint specified\\.$#" count: 1 @@ -5195,31 +4415,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\:\\:addColors\\(\\) has parameter \\$styleArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\\\PageSetup\\:\\:buildMarginSet\\(\\) has parameter \\$marginSet with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\\\PageSetup\\:\\:buildMarginSet\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Gnumeric\\\\PageSetup\\:\\:adjustMargins\\(\\) has parameter \\$marginSet with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric/PageSetup.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$formats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$rowspan has no typehint specified\\.$#" count: 1 @@ -5325,36 +4520,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementTitle\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$spanEtc has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementSpanEtc\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementHr\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementBr\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementA\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -5365,86 +4535,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementH1Etc\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementLi\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementImg\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementTable\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementTr\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 4 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementThTdOther\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementBgcolor\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementWidth\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Cannot call method setWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 3 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementHeight\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementAlign\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementVAlign\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementDataFormat\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:processDomElementThTd\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:applyInlineStyle\\(\\) has parameter \\$attributeArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Parameter \\#2 \\$styleValue of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:setBorderStyle\\(\\) expects string, string\\|null given\\.$#" count: 5 @@ -5470,21 +4570,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:insertImage\\(\\) has parameter \\$attributes with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$borderMappings has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:getBorderMappings\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Cannot call method getNamespaces\\(\\) on SimpleXMLElement\\|false\\.$#" count: 1 @@ -5500,11 +4590,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Ods.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods.php - - message: "#^Cannot call method getElementsByTagNameNS\\(\\) on DOMElement\\|null\\.$#" count: 2 @@ -5690,16 +4775,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Security/XmlScanner.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$formats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$fonts type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - message: "#^Parameter \\#1 \\$haystack of function substr_count expects string, string\\|false given\\.$#" count: 1 @@ -5710,11 +4785,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Slk.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$colorArray has no typehint specified\\.$#" count: 1 @@ -5725,11 +4795,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Slk.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processCRecord\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -5740,11 +4805,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Slk.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processFRecord\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$styleSettingsFont has no typehint specified\\.$#" count: 1 @@ -5755,16 +4815,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Slk.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:styleSettings\\(\\) has parameter \\$styleData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:addStyle\\(\\) has parameter \\$styleData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - message: "#^Parameter \\#1 \\$columnIndex of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:stringFromColumnIndex\\(\\) expects int, string given\\.$#" count: 3 @@ -5775,116 +4825,6 @@ parameters: count: 3 path: src/PhpSpreadsheet/Reader/Slk.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPRecord\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPColors\\(\\) has parameter \\$formatArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPFontStyles\\(\\) has parameter \\$formatArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:processPFinal\\(\\) has parameter \\$formatArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:columnRowFromRowData\\(\\) has parameter \\$rowData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$formats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$palette type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sheets type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$externalBooks type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$ref type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$externalNames type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$definedname type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sst type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$objs type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$textObjects type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$cellNotes type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$mapCellXfIndex type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$mapCellStyleXfIndex type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sharedFormulas type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:\\$sharedFormulaParts type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\|PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\\\BSE\\:\\:getDgContainer\\(\\)\\.$#" count: 1 @@ -6190,71 +5130,6 @@ parameters: count: 8 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:getSplicedRecordData\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:createFormulaFromTokens\\(\\) has parameter \\$tokens with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:getNextToken\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF8CellRangeAddressList\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF5CellRangeAddressList\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF8ConstantArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readBIFF8Constant\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readRGB\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readByteStringShort\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readByteStringLong\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readUnicodeStringShort\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readUnicodeStringLong\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:readUnicodeString\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Cannot access offset 1 on array\\|false\\.$#" count: 1 @@ -6270,46 +5145,21 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\:\\:map\\(\\) has parameter \\$palette with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls/Color.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\:\\:map\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls/Color.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF5\\:\\:\\$map has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF5\\:\\:lookup\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF5.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF8\\:\\:\\$map has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BIFF8\\:\\:lookup\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls/Color/BIFF8.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BuiltIn\\:\\:\\$map has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\Color\\\\BuiltIn\\:\\:lookup\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls/Color/BuiltIn.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\\\ErrorCode\\:\\:\\$map has no typehint specified\\.$#" count: 1 @@ -6445,11 +5295,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xls/Style/FillPattern.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - message: "#^Cannot access property \\$Relationship on SimpleXMLElement\\|false\\.$#" count: 12 @@ -6460,11 +5305,6 @@ parameters: count: 6 path: src/PhpSpreadsheet/Reader/Xlsx.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - message: "#^Cannot call method registerXPathNamespace\\(\\) on SimpleXMLElement\\|false\\.$#" count: 4 @@ -6845,11 +5685,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readHyperLinkDrawing\\(\\) has parameter \\$hyperlinks with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - message: "#^Offset 'id' does not exist on SimpleXMLElement\\|null\\.$#" count: 1 @@ -6870,11 +5705,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readFormControlProperties\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readPrinterSettings\\(\\) has parameter \\$dir with no typehint specified\\.$#" count: 1 @@ -6890,11 +5720,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:readPrinterSettings\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\AutoFilter\\:\\:\\$worksheet has no typehint specified\\.$#" count: 1 @@ -6965,11 +5790,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartTitle\\(\\) has parameter \\$namespacesChartMeta with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/Chart.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Chart\\:\\:chartLayoutDetails\\(\\) has no return typehint specified\\.$#" count: 1 @@ -7145,16 +5965,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:setColumnAttributes\\(\\) has parameter \\$columnAttributes with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:setRowAttributes\\(\\) has parameter \\$rowAttributes with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredColumn\\(\\) has no return typehint specified\\.$#" count: 1 @@ -7165,11 +5975,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredColumn\\(\\) has parameter \\$rowsAttributes with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:readColumnAttributes\\(\\) has no return typehint specified\\.$#" count: 1 @@ -7195,11 +6000,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredRow\\(\\) has parameter \\$columnsAttributes with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/ColumnAndRowAttributes.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ColumnAndRowAttributes\\:\\:isFilteredRow\\(\\) has parameter \\$rowCoordinate with no typehint specified\\.$#" count: 1 @@ -7230,11 +6030,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:__construct\\(\\) has parameter \\$dxfs with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:readConditionalStyles\\(\\) has no return typehint specified\\.$#" count: 1 @@ -7245,11 +6040,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:setConditionalStyles\\(\\) has parameter \\$conditionals with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/ConditionalStyles.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\ConditionalStyles\\:\\:setConditionalStyles\\(\\) has parameter \\$xmlExtLst with no typehint specified\\.$#" count: 1 @@ -7330,21 +6120,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:load\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:pageSetup\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:pageSetup\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/PageSetup.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:\\$securityScanner has no typehint specified\\.$#" count: 1 @@ -7400,11 +6180,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:getArrayItem\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx/Properties.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Properties\\:\\:getArrayItem\\(\\) has parameter \\$key with no typehint specified\\.$#" count: 1 @@ -7535,11 +6310,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/Styles.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$styles type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$fileContents has no typehint specified\\.$#" count: 1 @@ -7550,11 +6320,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:xmlMappings\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" count: 1 @@ -7570,11 +6335,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:listWorksheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Cannot call method getNamespaces\\(\\) on SimpleXMLElement\\|false\\.$#" count: 3 @@ -7585,11 +6345,6 @@ parameters: count: 3 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:listWorksheetInfo\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:identifyFixedStyleValue\\(\\) has no return typehint specified\\.$#" count: 1 @@ -7680,21 +6435,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyles\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:\\$borderPositions has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyleBorders\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:parseStyleBorders\\(\\) has parameter \\$styleID with no typehint specified\\.$#" count: 1 @@ -7715,16 +6460,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\\\PageSettings\\:\\:__construct\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml/PageSettings.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\\\PageSettings\\:\\:pageSetup\\(\\) has parameter \\$namespaces with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml/PageSettings.php - - message: "#^Parameter \\#2 \\$cmp_function of function uksort expects callable\\(mixed, mixed\\)\\: int, array\\('self', 'cellReverseSort'\\) given\\.$#" count: 4 @@ -7875,11 +6610,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/CodePage.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\CodePage\\:\\:getEncodings\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/CodePage.php - - message: "#^Parameter \\#1 \\$dateValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:timestampToExcel\\(\\) expects int, float\\|int\\|string given\\.$#" count: 1 @@ -8015,51 +6745,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Escher/DgContainer.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\:\\:\\$children type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\:\\:getChildren\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\:\\:\\$OPT type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DgContainer\\\\SpgrContainer\\\\SpContainer\\:\\:getOPTCollection\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DgContainer/SpgrContainer/SpContainer.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:\\$OPT type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:\\$IDCLs type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:getIDCLs\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\:\\:setIDCLs\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DggContainer.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Escher\\\\DggContainer\\\\BstoreContainer\\:\\:\\$BSECollection type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Escher/DggContainer/BstoreContainer.php - - message: "#^Strict comparison using \\=\\=\\= between string\\|false and null will always evaluate to false\\.$#" count: 1 @@ -8080,11 +6770,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Font.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:\\$defaultColumnWidths type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Font.php - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects int, float\\|int given\\.$#" count: 1 @@ -8125,86 +6810,26 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Font.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\CholeskyDecomposition\\:\\:\\$L type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/CholeskyDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$d type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$e has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$V type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$H type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$ort type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$cdivi has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:\\$A type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:getRealEigenvalues\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\EigenvalueDecomposition\\:\\:getImagEigenvalues\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/EigenvalueDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:\\$LU type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:\\$piv type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php - - message: "#^Else branch is unreachable because previous condition is always true\\.$#" count: 1 path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:getPivot\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\LUDecomposition\\:\\:getDoublePivot\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Shared/JAMA/LUDecomposition.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:\\$A type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:__construct\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 @@ -8215,11 +6840,6 @@ parameters: count: 19 path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:getArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\Matrix\\:\\:getMatrix\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 @@ -8310,31 +6930,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/JAMA/Matrix.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\QRDecomposition\\:\\:\\$QR type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\QRDecomposition\\:\\:\\$Rdiag type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/QRDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:\\$U type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:\\$V type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:\\$s type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php - - message: "#^Left side of && is always true\\.$#" count: 4 @@ -8345,26 +6940,6 @@ parameters: count: 7 path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\JAMA\\\\SingularValueDecomposition\\:\\:getSingularValues\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/JAMA/SingularValueDecomposition.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:\\$_list type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:\\$bbat type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:\\$sbat type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\:\\:getStream\\(\\) should return resource but returns resource\\|false\\.$#" count: 1 @@ -8465,36 +7040,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/OLE.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\ChainedBlockStream\\:\\:\\$params type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php - - message: "#^Parameter \\#1 \\$var of function count expects array\\|Countable, string given\\.$#" count: 1 path: src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\ChainedBlockStream\\:\\:stream_stat\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/ChainedBlockStream.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:\\$children type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:__construct\\(\\) has parameter \\$children with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\:\\:savePpsSetPnt\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS.php - - message: "#^Parameter \\#3 \\$length of function array_slice expects int\\|null, float given\\.$#" count: 1 @@ -8595,26 +7145,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:calcSize\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:saveBigData\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:makeSmallData\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLE\\\\PPS\\\\Root\\:\\:savePps\\(\\) has parameter \\$raList with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLE/PPS/Root.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$data has no typehint specified\\.$#" count: 1 @@ -8635,11 +7165,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/OLERead.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:\\$props type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/OLERead.php - - message: "#^Parameter \\#1 \\$data of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\OLERead\\:\\:getInt4d\\(\\) expects string, string\\|false given\\.$#" count: 8 @@ -8660,11 +7185,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/PasswordHasher.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:\\$SYLKCharacters type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/StringHelper.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:sanitizeUTF8\\(\\) should return string but returns string\\|false\\.$#" count: 1 @@ -8840,11 +7360,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Trend/BestFit.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\BestFit\\:\\:sumSquares\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Trend/BestFit.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Trend\\\\PolynomialBestFit\\:\\:getCoefficients\\(\\) has no return typehint specified\\.$#" count: 1 @@ -8920,51 +7435,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Xls.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Xls\\:\\:oneAnchor2twoAnchor\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Xls.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$workbookViewVisibilityValues has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Spreadsheet.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$ribbonBinObjects type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Spreadsheet.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$unparsedLoadedData type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Spreadsheet.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getRibbonXMLData\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Spreadsheet.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getUnparsedLoadedData\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Spreadsheet.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:setUnparsedLoadedData\\(\\) has parameter \\$unparsedLoadedData with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Spreadsheet.php - - message: "#^Call to function is_array\\(\\) with string will always evaluate to false\\.$#" count: 1 path: src/PhpSpreadsheet/Spreadsheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:getRibbonBinObjects\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Spreadsheet.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 1 @@ -9015,26 +7495,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Alignment.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Alignment.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Alignment.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Alignment.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Alignment\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Alignment.php - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\) given\\.$#" count: 1 @@ -9045,36 +7505,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Border.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\)\\.$#" count: 1 path: src/PhpSpreadsheet/Style/Border.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - message: "#^Right side of && is always true\\.$#" count: 1 path: src/PhpSpreadsheet/Style/Border.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Border\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Border.php - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\) given\\.$#" count: 10 @@ -9085,31 +7525,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Borders.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Borders.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Borders.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Borders.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Borders\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Borders.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:\\$indexedColors type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" count: 1 @@ -9130,36 +7545,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Color.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\)\\.$#" count: 1 path: src/PhpSpreadsheet/Style/Color.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:getColourComponent\\(\\) should return int\\|string but returns float\\|int\\|string\\.$#" count: 1 path: src/PhpSpreadsheet/Style/Color.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Color\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Color.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:\\$condition \\(array\\\\) does not accept array\\\\.$#" count: 1 @@ -9190,11 +7585,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBar.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:\\$axisColor type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:getXmlAttributes\\(\\) has no return typehint specified\\.$#" count: 1 @@ -9215,11 +7605,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBarExtension\\:\\:getAxisColor\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/ConditionalFormatting/ConditionalDataBarExtension.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalFormatValueObject\\:\\:\\$type has no typehint specified\\.$#" count: 1 @@ -9350,26 +7735,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Fill.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Fill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Fill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Fill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Fill\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Fill.php - - message: "#^Parameter \\#1 \\$parent of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:bindParent\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style, \\$this\\(PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\) given\\.$#" count: 1 @@ -9380,86 +7745,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Font.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Font.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Font.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Font.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$builtInFormats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$flippedBuiltInFormats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getSharedComponent\\(\\)\\.$#" count: 1 path: src/PhpSpreadsheet/Style/NumberFormat.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:\\$builtInFormatCode \\(int\\|false\\) does not accept bool\\|int\\.$#" count: 1 path: src/PhpSpreadsheet/Style/NumberFormat.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:toFormattedString\\(\\) has parameter \\$callBack with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:\\$dateFormatReplacements type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:\\$dateFormatReplacements24 type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:\\$dateFormatReplacements12 type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat/DateFormatter.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\DateFormatter\\:\\:format\\(\\) has parameter \\$value with no typehint specified\\.$#" count: 1 @@ -9555,11 +7850,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:toFormattedString\\(\\) has parameter \\$callBack with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat/Formatter.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\Formatter\\:\\:toFormattedString\\(\\) should return string but returns float\\|int\\|string\\.$#" count: 1 @@ -9595,11 +7885,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:mergeComplexNumberFormatMasks\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:processComplexNumberFormatMask\\(\\) has parameter \\$mask with no typehint specified\\.$#" count: 1 @@ -9640,11 +7925,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:formatStraightNumericValue\\(\\) has parameter \\$matches with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/NumberFormat/NumberFormatter.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\NumberFormat\\\\NumberFormatter\\:\\:formatStraightNumericValue\\(\\) has parameter \\$useThousands with no typehint specified\\.$#" count: 1 @@ -9695,26 +7975,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Protection.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Protection.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Protection.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Protection.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Protection\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Protection.php - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 3 @@ -9730,21 +7990,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Style.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\) has parameter \\$array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getStyleArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:applyFromArray\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 2 @@ -9770,46 +8015,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Style.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) has parameter \\$pStyles with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) has parameter \\$rangeEnd with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) has parameter \\$rangeStart with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getOldXfIndexes\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Style.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:exportArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Supervisor.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:exportArray1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Supervisor.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Supervisor\\:\\:exportArray2\\(\\) has parameter \\$exportedArray with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Style/Supervisor.php - - message: "#^Result of && is always true\\.$#" count: 1 @@ -9825,11 +8030,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:\\$fromReplace type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:\\$toReplace has no typehint specified\\.$#" count: 1 @@ -10070,16 +8270,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/MemoryDrawing.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$columnsToRepeatAtLeft type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$rowsToRepeatAtTop type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:\\$pageOrder has no typehint specified\\.$#" count: 1 @@ -10090,26 +8280,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getColumnsToRepeatAtLeft\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:setColumnsToRepeatAtLeft\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getRowsToRepeatAtTop\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:setRowsToRepeatAtTop\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/PageSetup.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\PageSetup\\:\\:getPrintArea\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -10155,11 +8325,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/SheetView.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$invalidCharacters type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$drawingCollection with generic class ArrayObject does not specify its types\\: TKey, TValue$#" count: 1 @@ -10170,26 +8335,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$conditionalStylesCollection type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$protectedCells type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$hyperlinkCollection type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:\\$dataValidationCollection type has no value type specified in iterable type array\\.$#" - 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 @@ -10210,11 +8355,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getInvalidCharacters\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getDrawingCollection\\(\\) return type with generic class ArrayObject does not specify its types\\: TKey, TValue$#" count: 1 @@ -10270,11 +8410,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getHighestRowAndColumn\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 4 @@ -10305,11 +8440,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getConditionalStylesCollection\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -10360,16 +8490,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:fromArray\\(\\) has parameter \\$source with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:rangeToArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 4 @@ -10395,11 +8515,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:namedRangeToArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Cannot call method getWorksheet\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\|null\\.$#" count: 1 @@ -10415,46 +8530,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:toArray\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:\\$enclosureRequired has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Csv.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:writeLine\\(\\) has parameter \\$pValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Csv.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$cssStyles type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$columnWidths type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$isSpannedCell type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$isBaseCell type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:\\$isSpannedRow type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Call to function array_key_exists\\(\\) with int and array\\('none' \\=\\> 'none', 'dashDot' \\=\\> '1px dashed', 'dashDotDot' \\=\\> '1px dotted', 'dashed' \\=\\> '1px dashed', 'dotted' \\=\\> '1px dotted', 'double' \\=\\> '3px double', 'hair' \\=\\> '1px solid', 'medium' \\=\\> '2px solid', \\.\\.\\.\\) will always evaluate to false\\.$#" count: 1 @@ -10525,11 +8605,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:extendRowsForCharts\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Parameter \\#1 \\$string of function htmlspecialchars expects string, string\\|null given\\.$#" count: 1 @@ -10575,31 +8650,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:buildCssRowHeights\\(\\) has parameter \\$css with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:buildCssPerSheet\\(\\) has parameter \\$css with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:buildCSS\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyle\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleAlignment\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Parameter \\#1 \\$vAlign of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:mapVAlign\\(\\) expects string, string\\|null given\\.$#" count: 1 @@ -10610,26 +8660,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleFont\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleBorders\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Parameter \\#1 \\$borderStyle of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:mapBorderStyle\\(\\) expects int, string given\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:createCSSStyleFill\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateHTMLFooter\\(\\) has no return typehint specified\\.$#" count: 1 @@ -10855,21 +8890,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:generateRow\\(\\) has parameter \\$pValues with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:assembleCSS\\(\\) has parameter \\$pValue with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:calculateSpansOmitRows\\(\\) has parameter \\$candidateSpannedRow with no typehint specified\\.$#" count: 1 @@ -10960,11 +8985,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Writer/Ods/Settings.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Pdf\\:\\:\\$paperSizes type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Pdf.php - - message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#" count: 1 @@ -10975,41 +8995,16 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Pdf/Dompdf.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Pdf\\\\Mpdf\\:\\:createExternalWriterInstance\\(\\) has parameter \\$config with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Pdf/Mpdf.php - - message: "#^Strict comparison using \\=\\=\\= between null and int will always evaluate to false\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Pdf/Mpdf.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Pdf\\\\Tcpdf\\:\\:createExternalWriterInstance\\(\\) has parameter \\$paperSize with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php - - message: "#^Strict comparison using \\=\\=\\= between int and null will always evaluate to false\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:\\$strTable type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:\\$colors type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:\\$IDCLs type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -11075,16 +9070,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:writeSummaryPropOle\\(\\) has parameter \\$dataSection with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\:\\:writeSummaryProp\\(\\) has parameter \\$dataSection with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls.php - - message: "#^Parameter \\#2 \\$pad_length of function str_pad expects int, float\\|int given\\.$#" count: 1 @@ -11105,16 +9090,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Escher.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:\\$spOffsets type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Escher.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:\\$spTypes type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Escher.php - - message: "#^If condition is always true\\.$#" count: 3 @@ -11125,16 +9100,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Escher.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:getSpOffsets\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Escher.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Escher\\:\\:getSpTypes\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Escher.php - - message: "#^Parameter \\#1 \\$name of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:getCharsetFromFontName\\(\\) expects string, string\\|null given\\.$#" count: 1 @@ -11160,26 +9125,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Font.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$externalSheets type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$references type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$ptg type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$functions type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:\\$spreadsheet has no typehint specified\\.$#" count: 1 @@ -11200,41 +9145,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:cellToPackedRowcol\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:rangeToPackedRange\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:cellToRowcol\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:advance\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:parenthesizedExpression\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:createTree\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Parser\\:\\:toReversePolish\\(\\) has parameter \\$tree with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - message: "#^Offset 'left' does not exist on \\(array&nonEmpty\\)\\|string\\.$#" count: 6 @@ -11250,61 +9165,11 @@ parameters: count: 7 path: src/PhpSpreadsheet/Writer/Xls/Parser.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$palette type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$addedFonts type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$numberFormats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$addedNumberFormats type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$worksheetSizes type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$worksheetOffsets type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$stringTable type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:\\$colors has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:__construct\\(\\) has parameter \\$colors with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:__construct\\(\\) has parameter \\$str_table with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Workbook\\:\\:writeWorkbook\\(\\) has parameter \\$pWorksheetSizes with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 1 @@ -11345,41 +9210,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Workbook.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$columnInfo type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$selection type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$stringTable type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$colors has no typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:\\$fontHashIndex type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:__construct\\(\\) has parameter \\$colors with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:__construct\\(\\) has parameter \\$str_table with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Parameter \\#2 \\$height of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeRow\\(\\) expects int, float given\\.$#" count: 1 @@ -11430,11 +9265,6 @@ parameters: count: 3 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeRichTextString\\(\\) has parameter \\$arrcRun with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Parameter \\#2 \\$pieces of function implode expects array, array\\\\|false given\\.$#" count: 1 @@ -11455,11 +9285,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeColinfo\\(\\) has parameter \\$col_array with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Parameter \\#1 \\$hexadecimal_number of function hexdec expects string, array given\\.$#" count: 1 @@ -11485,11 +9310,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:processBitmapGd\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Parameter \\#1 \\$im of function imagesx expects resource, GdImage\\|resource given\\.$#" count: 1 @@ -11520,11 +9340,6 @@ parameters: count: 3 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:processBitmap\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Parameter \\#2 \\$length of function fread expects int, int\\|false given\\.$#" count: 1 @@ -11630,11 +9445,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:addZipFiles\\(\\) has parameter \\$zipContent with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:\\$calculateCellValues has no typehint specified\\.$#" count: 1 @@ -11750,11 +9560,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:getChartType\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeries and null will always evaluate to false\\.$#" count: 1 @@ -11795,11 +9600,6 @@ parameters: count: 6 path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Comments\\:\\:writeComment\\(\\) has parameter \\$pAuthors with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Comments.php - - message: "#^Parameter \\#1 \\$string of function substr expects string, int given\\.$#" count: 1 @@ -12000,16 +9800,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\StringTable\\:\\:flipStringTable\\(\\) has parameter \\$stringTable with no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\StringTable\\:\\:flipStringTable\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" count: 22 @@ -12215,51 +10005,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:\\$locale has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:providerBinaryComparisonOperation\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:testGetFunctions\\(\\) has parameter \\$functionCall with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:providerGetFunctions\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:providerCanLoadAllSupportedLocales\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertCount\\(\\) expects Countable\\|iterable, array\\|bool given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot access offset 2 on array\\|bool\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot access offset 4 on array\\|bool\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 9 @@ -12280,31 +10025,11 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - message: "#^Argument of an invalid type array\\|bool supplied for foreach, only iterables are supported\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - message: "#^Cannot call method getWorksheet\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\CalculationTest\\:\\:dataProviderBranchPruningFullExecution\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 4 @@ -12316,33 +10041,8 @@ parameters: path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\DefinedNamesCalculationTest\\:\\:namedRangeCalculationTest1\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\DefinedNamesCalculationTest\\:\\:namedRangeCalculationTest2\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:\\$spreadSheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerRangeEvaluation\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerNamedRangeEvaluation\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerUTF8NamedRangeEvaluation\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - @@ -12350,11 +10050,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Engine\\\\RangeTest\\:\\:providerCompositeNamedRangeEvaluation\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -12366,400 +10061,225 @@ parameters: path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FormulaAsStringTest\\:\\:providerFunctionsAsString\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DAverageTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DAverageTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DAverageTest\\:\\:providerDAverage\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountATest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountATest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountATest\\:\\:providerDCountA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:database3\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DCountTest\\:\\:providerDCount\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DGetTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DGetTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DGetTest\\:\\:providerDGet\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMaxTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMaxTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMaxTest\\:\\:providerDMax\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMinTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMinTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DMinTest\\:\\:providerDMin\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DProductTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DProductTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DProductTest\\:\\:providerDProduct\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevPTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevPTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevPTest\\:\\:providerDStDevP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DStDevTest\\:\\:providerDStDev\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DSumTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DSumTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DSumTest\\:\\:providerDSum\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarPTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarPTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarPTest\\:\\:providerDVarP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarTest\\:\\:database1\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarTest\\:\\:database2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Database\\\\DVarTest\\:\\:providerDVar\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$excelCalendar has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$returnDateType has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$spreadsheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\AllSetupTeardown\\:\\:\\$sheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DateDifTest\\:\\:providerDATEDIF\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DateTest\\:\\:providerDATE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DateValueTest\\:\\:providerDATEVALUE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DayTest\\:\\:providerDAY\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DayTest\\:\\:providerDAYOpenOffice\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\Days360Test\\:\\:providerDAYS360\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\DaysTest\\:\\:providerDAYS\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\EDateTest\\:\\:providerEDATE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\EoMonthTest\\:\\:providerEOMONTH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\HourTest\\:\\:providerHOUR\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\IsoWeekNumTest\\:\\:providerISOWEEKNUM\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\IsoWeekNumTest\\:\\:providerISOWEEKNUM1904\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\MinuteTest\\:\\:providerMINUTE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\MonthTest\\:\\:providerMONTH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\NetworkDaysTest\\:\\:testNETWORKDAYS\\(\\) has parameter \\$arg3 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\NetworkDaysTest\\:\\:providerNETWORKDAYS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\SecondTest\\:\\:providerSECOND\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\TimeTest\\:\\:providerTIME\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\TimeValueTest\\:\\:providerTIMEVALUE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WeekDayTest\\:\\:providerWEEKDAY\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TodayTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php - - message: "#^Parameter \\#1 \\$dateValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\DateTimeExcel\\\\WeekDay\\:\\:funcWeekDay\\(\\) expects float\\|int\\|string, null given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WeekNumTest\\:\\:providerWEEKNUM\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WeekNumTest\\:\\:providerWEEKNUM1904\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WorkDayTest\\:\\:testWORKDAY\\(\\) has parameter \\$arg3 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\WorkDayTest\\:\\:providerWORKDAY\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 7 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\YearFracTest\\:\\:providerYEARFRAC\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\DateTime\\\\YearTest\\:\\:providerYEAR\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselITest\\:\\:testBESSELI\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselITest\\:\\:providerBESSELI\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselJTest\\:\\:testBESSELJ\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselJTest\\:\\:providerBESSEJ\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselKTest\\:\\:testBESSELK\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselKTest\\:\\:providerBESSELK\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselYTest\\:\\:testBESSELY\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BesselYTest\\:\\:providerBESSELY\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2DecTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -12770,16 +10290,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2DecTest\\:\\:providerBIN2DEC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2HexTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -12790,16 +10300,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2HexTest\\:\\:providerBIN2HEX\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2OctTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -12810,11 +10310,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Bin2OctTest\\:\\:providerBIN2OCT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -12825,11 +10320,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitAndTest\\:\\:providerBITAND\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -12840,11 +10330,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitLShiftTest\\:\\:providerBITLSHIFT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -12855,11 +10340,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitOrTest\\:\\:providerBITOR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -12870,11 +10350,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitRShiftTest\\:\\:providerBITRSHIFT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -12885,36 +10360,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\BitXorTest\\:\\:providerBITXOR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ComplexTest\\:\\:testCOMPLEX\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ComplexTest\\:\\:providerCOMPLEX\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ConvertUoMTest\\:\\:testCONVERTUOM\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ConvertUoMTest\\:\\:providerCONVERTUOM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2BinTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -12925,16 +10370,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2BinTest\\:\\:providerDEC2BIN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2HexTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -12945,16 +10380,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2HexTest\\:\\:providerDEC2HEX\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2OctTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -12965,66 +10390,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Dec2OctTest\\:\\:providerDEC2OCT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\DeltaTest\\:\\:testDELTA\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\DeltaTest\\:\\:providerDELTA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfCTest\\:\\:testERFC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfCTest\\:\\:providerERFC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfPreciseTest\\:\\:testERFPRECISE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfPreciseTest\\:\\:providerERFPRECISE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfTest\\:\\:testERF\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ErfTest\\:\\:providerERF\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\GeStepTest\\:\\:testGESTEP\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\GeStepTest\\:\\:providerGESTEP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2BinTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -13035,16 +10400,6 @@ parameters: count: 6 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2BinTest\\:\\:providerHEX2BIN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2DecTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -13055,16 +10410,6 @@ parameters: count: 6 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2DecTest\\:\\:providerHEX2DEC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2OctTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -13075,166 +10420,6 @@ parameters: count: 6 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Hex2OctTest\\:\\:providerHEX2OCT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImAbsTest\\:\\:providerIMABS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImAbsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImArgumentTest\\:\\:providerIMARGUMENT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImArgumentTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImConjugateTest\\:\\:providerIMCONJUGATE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCosTest\\:\\:providerIMCOS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCoshTest\\:\\:providerIMCOSH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCotTest\\:\\:providerIMCOT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCscTest\\:\\:providerIMCSC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImCschTest\\:\\:providerIMCSCH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImDivTest\\:\\:testIMDIV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImDivTest\\:\\:providerIMDIV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImExpTest\\:\\:providerIMEXP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImLnTest\\:\\:providerIMLN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImLog10Test\\:\\:providerIMLOG10\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImLog2Test\\:\\:providerIMLOG2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImPowerTest\\:\\:testIMPOWER\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImPowerTest\\:\\:providerIMPOWER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImProductTest\\:\\:testIMPRODUCT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImProductTest\\:\\:providerIMPRODUCT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImRealTest\\:\\:providerIMREAL\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImRealTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSecTest\\:\\:providerIMSEC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSechTest\\:\\:providerIMSECH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSinTest\\:\\:providerIMSIN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSinhTest\\:\\:providerIMSINH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSqrtTest\\:\\:providerIMSQRT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSubTest\\:\\:testIMSUB\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSubTest\\:\\:providerIMSUB\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSumTest\\:\\:testIMSUM\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImSumTest\\:\\:providerIMSUM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImTanTest\\:\\:providerIMTAN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\ImaginaryTest\\:\\:providerIMAGINARY\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImaginaryTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2BinTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -13245,16 +10430,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2BinTest\\:\\:providerOCT2BIN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2DecTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -13265,16 +10440,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2DecTest\\:\\:providerOCT2DEC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2HexTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -13286,2125 +10451,760 @@ parameters: path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Engineering\\\\Oct2HexTest\\:\\:providerOCT2HEX\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintMTest\\:\\:testACCRINTM\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintMTest\\:\\:providerACCRINTM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintTest\\:\\:testACCRINT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AccrintTest\\:\\:providerACCRINT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorDegRcTest\\:\\:testAMORDEGRC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorDegRcTest\\:\\:providerAMORDEGRC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorLincTest\\:\\:testAMORLINC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\AmorLincTest\\:\\:providerAMORLINC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDayBsTest\\:\\:testCOUPDAYBS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDayBsTest\\:\\:providerCOUPDAYBS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysNcTest\\:\\:testCOUPDAYSNC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysNcTest\\:\\:providerCOUPDAYSNC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysTest\\:\\:testCOUPDAYS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupDaysTest\\:\\:providerCOUPDAYS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNcdTest\\:\\:testCOUPNCD\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNcdTest\\:\\:providerCOUPNCD\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNumTest\\:\\:testCOUPNUM\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupNumTest\\:\\:providerCOUPNUM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupPcdTest\\:\\:testCOUPPCD\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CoupPcdTest\\:\\:providerCOUPPCD\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumIpmtTest\\:\\:testCUMIPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumIpmtTest\\:\\:providerCUMIPMT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumPrincTest\\:\\:testCUMPRINC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\CumPrincTest\\:\\:providerCUMPRINC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DbTest\\:\\:testDB\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DbTest\\:\\:providerDB\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DdbTest\\:\\:testDDB\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DdbTest\\:\\:providerDDB\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DiscTest\\:\\:testDISC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DiscTest\\:\\:providerDISC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarDeTest\\:\\:testDOLLARDE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarDeTest\\:\\:providerDOLLARDE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarFrTest\\:\\:testDOLLARFR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\DollarFrTest\\:\\:providerDOLLARFR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\EffectTest\\:\\:providerEFFECT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvScheduleTest\\:\\:testFVSCHEDULE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvScheduleTest\\:\\:providerFVSCHEDULE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvTest\\:\\:testFV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\FvTest\\:\\:providerFV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php - - - - message: "#^Parameter \\#3 \\$message of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) expects string, float given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\HelpersTest\\:\\:providerDaysPerYear\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IPmtTest\\:\\:testIPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IPmtTest\\:\\:providerIPMT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IntRateTest\\:\\:testINTRATE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IntRateTest\\:\\:providerINTRATE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IrrTest\\:\\:testIRR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IrrTest\\:\\:providerIRR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IsPmtTest\\:\\:testISPMT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\IsPmtTest\\:\\:providerISPMT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\MirrTest\\:\\:testMIRR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\MirrTest\\:\\:providerMIRR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NPerTest\\:\\:testNPER\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NPerTest\\:\\:providerNPER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NominalTest\\:\\:providerNOMINAL\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NpvTest\\:\\:testNPV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\NpvTest\\:\\:providerNPV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PDurationTest\\:\\:testPDURATION\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PDurationTest\\:\\:providerPDURATION\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PmtTest\\:\\:testPMT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PmtTest\\:\\:providerPMT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PpmtTest\\:\\:testPPMT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PpmtTest\\:\\:providerPPMT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceDiscTest\\:\\:testPRICEDISC\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceDiscTest\\:\\:providerPRICEDISC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceMatTest\\:\\:testPRICEMAT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceMatTest\\:\\:providerPRICEMAT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:testPRICE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:providerPRICE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:testPRICE3\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PriceTest\\:\\:providerPRICE3\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PvTest\\:\\:testPV\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\PvTest\\:\\:providerPV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RateTest\\:\\:testRATE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RateTest\\:\\:providerRATE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\ReceivedTest\\:\\:testRECEIVED\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\ReceivedTest\\:\\:providerRECEIVED\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RriTest\\:\\:testRRI\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\RriTest\\:\\:providerRRI\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SlnTest\\:\\:testSLN\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SlnTest\\:\\:providerSLN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SydTest\\:\\:testSYD\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\SydTest\\:\\:providerSYD\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillEqTest\\:\\:testTBILLEQ\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillEqTest\\:\\:providerTBILLEQ\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillPriceTest\\:\\:testTBILLPRICE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillPriceTest\\:\\:providerTBILLPRICE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillYieldTest\\:\\:testTBILLYIELD\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\TBillYieldTest\\:\\:providerTBILLYIELD\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XNpvTest\\:\\:testXNPV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XNpvTest\\:\\:providerXNPV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XirrTest\\:\\:testXIRR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\XirrTest\\:\\:providerXIRR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldDiscTest\\:\\:testYIELDDISC\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldDiscTest\\:\\:providerYIELDDISC\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldMatTest\\:\\:testYIELDMAT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Financial\\\\YieldMatTest\\:\\:providerYIELDMAT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\AndTest\\:\\:testAND\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\AndTest\\:\\:providerAND\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfErrorTest\\:\\:providerIFERROR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfNaTest\\:\\:providerIFNA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfTest\\:\\:testIF\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfTest\\:\\:providerIF\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\IfsTest\\:\\:providerIFS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\NotTest\\:\\:testNOT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\NotTest\\:\\:providerNOT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\OrTest\\:\\:testOR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\OrTest\\:\\:providerOR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\SwitchTest\\:\\:testSWITCH\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\SwitchTest\\:\\:providerSwitch\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\XorTest\\:\\:testXOR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Logical\\\\XorTest\\:\\:providerXOR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\AddressTest\\:\\:testADDRESS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\AddressTest\\:\\:providerADDRESS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ChooseTest\\:\\:testCHOOSE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ChooseTest\\:\\:providerCHOOSE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ColumnTest\\:\\:providerCOLUMN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ColumnsTest\\:\\:testCOLUMNS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\ColumnsTest\\:\\:providerCOLUMNS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\HLookupTest\\:\\:testHLOOKUP\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\HLookupTest\\:\\:providerHLOOKUP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\IndexTest\\:\\:testINDEX\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\IndexTest\\:\\:providerINDEX\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\IndirectTest\\:\\:providerINDIRECT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\LookupTest\\:\\:testLOOKUP\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\LookupTest\\:\\:providerLOOKUP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\MatchTest\\:\\:testMATCH\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\MatchTest\\:\\:providerMATCH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\OffsetTest\\:\\:providerOFFSET\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\RowTest\\:\\:providerROW\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\RowsTest\\:\\:testROWS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\RowsTest\\:\\:providerROWS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\TransposeTest\\:\\:providerTRANSPOSE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\VLookupTest\\:\\:testVLOOKUP\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\LookupRef\\\\VLookupTest\\:\\:providerVLOOKUP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AbsTest\\:\\:providerAbs\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcosTest\\:\\:providerAcos\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcoshTest\\:\\:providerAcosh\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcotTest\\:\\:providerACOT\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AcothTest\\:\\:providerACOTH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AllSetupTeardown\\:\\:\\$compatibilityMode has no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php + + - + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AllSetupTeardown\\:\\:\\$spreadsheet has no typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AllSetupTeardown\\:\\:\\$sheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ArabicTest\\:\\:providerARABIC\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AsinTest\\:\\:providerAsin\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AsinhTest\\:\\:providerAsinh\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\Atan2Test\\:\\:providerATAN2\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AtanTest\\:\\:providerAtan\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\AtanhTest\\:\\:providerAtanh\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\BaseTest\\:\\:providerBASE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 7 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CeilingMathTest\\:\\:providerCEILINGMATH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CeilingPreciseTest\\:\\:providerFLOORPRECISE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CeilingTest\\:\\:providerCEILING\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CombinATest\\:\\:providerCOMBINA\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CombinTest\\:\\:providerCOMBIN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CosTest\\:\\:providerCos\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CoshTest\\:\\:providerCosh\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CotTest\\:\\:providerCOT\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CothTest\\:\\:providerCOTH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CscTest\\:\\:providerCSC\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\CschTest\\:\\:providerCSCH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\DegreesTest\\:\\:providerDegrees\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\EvenTest\\:\\:providerEVEN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ExpTest\\:\\:providerEXP\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FactDoubleTest\\:\\:providerFACTDOUBLE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FactTest\\:\\:providerFACT\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 6 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FactTest\\:\\:providerFACTGnumeric\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FloorMathTest\\:\\:providerFLOORMATH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FloorPreciseTest\\:\\:providerFLOORPRECISE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\FloorTest\\:\\:providerFLOOR\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\GcdTest\\:\\:testGCD\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\GcdTest\\:\\:providerGCD\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\IntTest\\:\\:providerINT\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LcmTest\\:\\:testLCM\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LcmTest\\:\\:providerLCM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LnTest\\:\\:providerLN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\Log10Test\\:\\:providerLN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\LogTest\\:\\:providerLOG\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MInverseTest\\:\\:testMINVERSE\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MInverseTest\\:\\:providerMINVERSE\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MMultTest\\:\\:testMMULT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 9 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MMultTest\\:\\:providerMMULT\\(\\) has no return typehint specified\\.$#" - count: 1 + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MRoundTest\\:\\:providerMROUND\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MdeTermTest\\:\\:providerMDETERM\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ModTest\\:\\:providerMOD\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MultinomialTest\\:\\:testMULTINOMIAL\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\MultinomialTest\\:\\:providerMULTINOMIAL\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\OddTest\\:\\:providerODD\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\PowerTest\\:\\:providerPOWER\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ProductTest\\:\\:testPRODUCT\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\ProductTest\\:\\:providerPRODUCT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\QuotientTest\\:\\:providerQUOTIENT\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RadiansTest\\:\\:providerRADIANS\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RandBetweenTest\\:\\:providerRANDBETWEEN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RomanTest\\:\\:providerROMAN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RoundDownTest\\:\\:providerRoundDown\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RoundTest\\:\\:providerRound\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\RoundUpTest\\:\\:providerRoundUp\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SecTest\\:\\:providerSEC\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SechTest\\:\\:providerSECH\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SeriesSumTest\\:\\:testSERIESSUM\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 5 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SeriesSumTest\\:\\:providerSERIESSUM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SignTest\\:\\:providerSIGN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SinTest\\:\\:providerSin\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SinhTest\\:\\:providerCosh\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SqrtPiTest\\:\\:providerSQRTPI\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SqrtTest\\:\\:providerSqrt\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SubTotalTest\\:\\:providerSUBTOTAL\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 4 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php + + - + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SubTotalTest\\:\\:providerSUBTOTALHIDDEN\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfTest\\:\\:testSUMIF2\\(\\) has parameter \\$array1 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 3 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php + + - + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfTest\\:\\:testSUMIF2\\(\\) has parameter \\$array2 with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfTest\\:\\:providerSUMIF\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfsTest\\:\\:testSUMIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumIfsTest\\:\\:providerSUMIFS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumProductTest\\:\\:testSUMPRODUCT\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumProductTest\\:\\:providerSUMPRODUCT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumSqTest\\:\\:testSUMSQ\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumSqTest\\:\\:providerSUMSQ\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumTest\\:\\:testSUM\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumTest\\:\\:providerSUM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2MY2Test\\:\\:testSUMX2MY2\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2MY2Test\\:\\:testSUMX2MY2\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2MY2Test\\:\\:providerSUMX2MY2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2PY2Test\\:\\:testSUMX2PY2\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2PY2Test\\:\\:testSUMX2PY2\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumX2PY2Test\\:\\:providerSUMX2PY2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumXMY2Test\\:\\:testSUMXMY2\\(\\) has parameter \\$matrixData1 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumXMY2Test\\:\\:testSUMXMY2\\(\\) has parameter \\$matrixData2 with no value type specified in iterable type array\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\SumXMY2Test\\:\\:providerSUMXMY2\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\TanTest\\:\\:providerTan\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\TanhTest\\:\\:providerTanh\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\MathTrig\\\\TruncTest\\:\\:providerTRUNC\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php + + - + message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AveDevTest\\:\\:testAVEDEV\\(\\) has parameter \\$args with no typehint specified\\.$#" + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AveDevTest\\:\\:providerAVEDEV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageATest\\:\\:testAVERAGEA\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageATest\\:\\:providerAVERAGEA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfTest\\:\\:testAVERAGEIF\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfTest\\:\\:providerAVERAGEIF\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfsTest\\:\\:testAVERAGEIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageIfsTest\\:\\:providerAVERAGEIFS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageTest\\:\\:testAVERAGE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\AverageTest\\:\\:providerAVERAGE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaDistTest\\:\\:testBETADIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaDistTest\\:\\:providerBETADIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaInvTest\\:\\:testBETAINV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BetaInvTest\\:\\:providerBETAINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistRangeTest\\:\\:testBINOMDISTRANGE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistRangeTest\\:\\:providerBINOMDISTRANGE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistTest\\:\\:testBINOMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomDistTest\\:\\:providerBINOMDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomInvTest\\:\\:testBINOMINV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\BinomInvTest\\:\\:providerBINOMINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistLeftTailTest\\:\\:testCHIDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistLeftTailTest\\:\\:providerCHIDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistRightTailTest\\:\\:testCHIDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiDistRightTailTest\\:\\:providerCHIDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiInvLeftTailTest\\:\\:providerCHIINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiInvRightTailTest\\:\\:providerCHIINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ChiTestTest\\:\\:providerCHITEST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ConfidenceTest\\:\\:testCONFIDENCE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ConfidenceTest\\:\\:providerCONFIDENCE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CorrelTest\\:\\:providerCORREL\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CorrelTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountATest\\:\\:testCOUNTA\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountATest\\:\\:providerCOUNTA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountBlankTest\\:\\:testCOUNTBLANK\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountBlankTest\\:\\:providerCOUNTBLANK\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfTest\\:\\:testCOUNTIF\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfTest\\:\\:providerCOUNTIF\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfsTest\\:\\:testCOUNTIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountIfsTest\\:\\:providerCOUNTIFS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testBasicCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerBasicCOUNT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testExcelCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerExcelCOUNT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testOpenOfficeCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerOpenOfficeCOUNT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:testGnumericCOUNT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CountTest\\:\\:providerGnumericCOUNT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CovarTest\\:\\:testCOVAR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\CovarTest\\:\\:providerCOVAR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ExponDistTest\\:\\:testEXPONDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ExponDistTest\\:\\:providerEXPONDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FDistTest\\:\\:testFDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FDistTest\\:\\:providerFDIST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FisherInvTest\\:\\:providerFISHERINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\FisherTest\\:\\:providerFISHER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ForecastTest\\:\\:testFORECAST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ForecastTest\\:\\:providerFORECAST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaDistTest\\:\\:testGAMMADIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaDistTest\\:\\:providerGAMMADIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaInvTest\\:\\:testGAMMAINV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaInvTest\\:\\:providerGAMMAINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaLnTest\\:\\:providerGAMMALN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GammaTest\\:\\:providerGAMMA\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GaussTest\\:\\:providerGAUSS\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GaussTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GeoMeanTest\\:\\:testGEOMEAN\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GeoMeanTest\\:\\:providerGEOMEAN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GrowthTest\\:\\:testGROWTH\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\GrowthTest\\:\\:providerGROWTH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HarMeanTest\\:\\:testHARMEAN\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HarMeanTest\\:\\:providerHARMEAN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HypGeomDistTest\\:\\:testHYPGEOMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\HypGeomDistTest\\:\\:providerHYPGEOMDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\InterceptTest\\:\\:testINTERCEPT\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\InterceptTest\\:\\:testINTERCEPT\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\InterceptTest\\:\\:providerINTERCEPT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\KurtTest\\:\\:testKURT\\(\\) has parameter \\$values with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\KurtTest\\:\\:providerKURT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LargeTest\\:\\:providerLARGE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php - - - - message: "#^Cannot access offset int on array\\|int\\|string\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LinEstTest\\:\\:providerLINEST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php - - - - message: "#^Cannot access offset int on array\\|int\\|string\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogEstTest\\:\\:providerLOGEST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogInvTest\\:\\:testLOGINV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogInvTest\\:\\:providerLOGINV\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDist2Test\\:\\:testLOGNORMDIST2\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDist2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDist2Test\\:\\:providerLOGNORMDIST2\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDist2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDistTest\\:\\:testLOGNORMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\LogNormDistTest\\:\\:providerLOGNORMDIST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogNormDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxATest\\:\\:testMAXA\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxATest\\:\\:providerMAXA\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxIfsTest\\:\\:testMAXIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxIfsTest\\:\\:providerMAXIFS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxTest\\:\\:testMAX\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MaxTest\\:\\:providerMAX\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MedianTest\\:\\:testMEDIAN\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MedianTest\\:\\:providerMEDIAN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinATest\\:\\:testMINA\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinATest\\:\\:providerMINA\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinIfsTest\\:\\:testMINIFS\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinIfsTest\\:\\:providerMINIFS\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinTest\\:\\:testMIN\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\MinTest\\:\\:providerMIN\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinTest.php + path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 3 path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ModeTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ModeTest\\:\\:providerMODE\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ModeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NegBinomDistTest\\:\\:testNEGBINOMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NegBinomDistTest\\:\\:providerNEGBINOMDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormDistTest\\:\\:testNORMDIST\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormDistTest\\:\\:providerNORMDIST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormInvTest\\:\\:testNORMINV\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormInvTest\\:\\:providerNORMINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSDist2Test\\:\\:testNORMSDIST2\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSDist2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSDist2Test\\:\\:providerNORMSDIST2\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSDist2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSDistTest\\:\\:providerNORMSDIST\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\NormSInvTest\\:\\:providerNORMSINV\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormSInvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PercentRankTest\\:\\:providerPERCENTRANK\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PercentileTest\\:\\:testPERCENTILE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PercentileTest\\:\\:providerPERCENTILE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutTest\\:\\:testPERMUT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutTest\\:\\:providerPERMUT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutationATest\\:\\:testPERMUT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PermutationATest\\:\\:providerPERMUT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PoissonTest\\:\\:testPOISSON\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\PoissonTest\\:\\:providerPOISSON\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\QuartileTest\\:\\:testQUARTILE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\QuartileTest\\:\\:providerQUARTILE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RankTest\\:\\:providerRANK\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RsqTest\\:\\:testRSQ\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RsqTest\\:\\:testRSQ\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\RsqTest\\:\\:providerRSQ\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SkewTest\\:\\:testSKEW\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SkewTest\\:\\:providerSKEW\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SlopeTest\\:\\:testSLOPE\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SlopeTest\\:\\:testSLOPE\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SlopeTest\\:\\:providerSLOPE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SmallTest\\:\\:providerSMALL\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevATest\\:\\:providerSTDEVA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevATest\\:\\:providerOdsSTDEVA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPATest\\:\\:providerSTDEVPA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPATest\\:\\:providerOdsSTDEVPA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPTest\\:\\:providerSTDEVP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevPTest\\:\\:providerOdsSTDEVP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevTest\\:\\:providerSTDEV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StDevTest\\:\\:providerOdsSTDEV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StandardizeTest\\:\\:testSTANDARDIZE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StandardizeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\StandardizeTest\\:\\:providerSTANDARDIZE\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StandardizeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SteyxTest\\:\\:testSTEYX\\(\\) has parameter \\$xargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SteyxTest\\:\\:testSTEYX\\(\\) has parameter \\$yargs with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\SteyxTest\\:\\:providerSTEYX\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TDistTest\\:\\:providerTDIST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TinvTest\\:\\:providerTINV\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrendTest\\:\\:testTREND\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrendTest\\:\\:providerGROWTH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrimMeanTest\\:\\:testTRIMMEAN\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\TrimMeanTest\\:\\:providerTRIMMEAN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarATest\\:\\:providerVARA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarATest\\:\\:providerOdsVARA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPATest\\:\\:providerVARPA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPATest\\:\\:providerOdsVARPA\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPTest\\:\\:providerVARP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarPTest\\:\\:providerOdsVARP\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarTest\\:\\:providerVAR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\VarTest\\:\\:providerOdsVAR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\WeibullTest\\:\\:providerWEIBULL\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Statistical\\\\ZTestTest\\:\\:providerZTEST\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\CharTest\\:\\:providerCHAR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\CleanTest\\:\\:providerCLEAN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\CodeTest\\:\\:providerCODE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ConcatenateTest\\:\\:testCONCATENATE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ConcatenateTest\\:\\:providerCONCATENATE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\DollarTest\\:\\:testDOLLAR\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\DollarTest\\:\\:providerDOLLAR\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ExactTest\\:\\:testEXACT\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ExactTest\\:\\:providerEXACT\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FindTest\\:\\:testFIND\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FindTest\\:\\:providerFIND\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FixedTest\\:\\:testFIXED\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\FixedTest\\:\\:providerFIXED\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LeftTest\\:\\:testLEFT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LeftTest\\:\\:providerLEFT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LeftTest\\:\\:providerLocaleLEFT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LenTest\\:\\:providerLEN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LowerTest\\:\\:providerLOWER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\LowerTest\\:\\:providerLocaleLOWER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\MidTest\\:\\:testMID\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\MidTest\\:\\:providerMID\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\MidTest\\:\\:providerLocaleMID\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\NumberValueTest\\:\\:testNUMBERVALUE\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\NumberValueTest\\:\\:providerNUMBERVALUE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ProperTest\\:\\:providerPROPER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ProperTest\\:\\:providerLocaleLOWER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ReplaceTest\\:\\:testREPLACE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ReplaceTest\\:\\:providerREPLACE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -15415,311 +11215,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ReptTest\\:\\:providerREPT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\RightTest\\:\\:testRIGHT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\RightTest\\:\\:providerRIGHT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\RightTest\\:\\:providerLocaleRIGHT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SearchTest\\:\\:testSEARCH\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SearchTest\\:\\:providerSEARCH\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SubstituteTest\\:\\:testSUBSTITUTE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\SubstituteTest\\:\\:providerSUBSTITUTE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TTest\\:\\:providerT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextJoinTest\\:\\:testTEXTJOIN\\(\\) has parameter \\$args with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextJoinTest\\:\\:providerTEXTJOIN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextTest\\:\\:testTEXT\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TextTest\\:\\:providerTEXT\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\TrimTest\\:\\:providerTRIM\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\UpperTest\\:\\:providerUPPER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\UpperTest\\:\\:providerLocaleLOWER\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:\\$currencyCode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\TextData\\\\ValueTest\\:\\:providerVALUE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Web\\\\WebServiceTest\\:\\:testWEBSERVICE\\(\\) has parameter \\$responseData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Web/WebServiceTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\Functions\\\\Web\\\\WebServiceTest\\:\\:providerWEBSERVICE\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Web/WebServiceTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:\\$returnDate has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsBlank\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsBlank\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsErr\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsErr\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsError\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsError\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testErrorType\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerErrorType\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsLogical\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsLogical\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsNa\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsNa\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsNumber\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsNumber\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsText\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsText\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsNonText\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsNonText\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsEven\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsEven\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIsOdd\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsOdd\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testTYPE\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerTYPE\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testN\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerN\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIsFormula\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:testIfCondition\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\FunctionsTest\\:\\:providerIfCondition\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\LookupRefTest\\:\\:providerFormulaText\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\TranslationTest\\:\\:\\$compatibilityMode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/TranslationTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\TranslationTest\\:\\:\\$returnDate has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/TranslationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Calculation\\\\TranslationTest\\:\\:providerTranslations\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/TranslationTest.php - - message: "#^Cannot call method setAutoSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -15730,76 +11230,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerR1C1ConversionToA1Absolute\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerR1C1ConversionToA1Relative\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerR1C1ConversionToA1Exception\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerA1ConversionToR1C1Absolute\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerA1ConversionToR1C1Relative\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AddressHelperTest\\:\\:providerA1ConversionToR1C1Exception\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:\\$currencyCode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:currencyProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:fractionProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:percentageProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:timeProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\AdvancedValueBinderTest\\:\\:stringProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 @@ -15810,116 +11240,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CellTest\\:\\:providerSetValueExplicit\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CellTest\\:\\:providerSetValueExplicitException\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerColumnString\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerColumnIndex\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerCoordinates\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:testIndexesFromString\\(\\) has parameter \\$expectedResult with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerIndexesFromString\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerAbsoluteCoordinates\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerAbsoluteReferences\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerSplitRange\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerBuildRange\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Parameter \\#1 \\$pRange of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:buildRange\\(\\) expects array, null given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerRangeBoundaries\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerRangeDimension\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerGetRangeBoundaries\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:testExtractAllCellReferencesInRange\\(\\) has parameter \\$expectedResult with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerExtractAllCellReferencesInRange\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerInvalidRange\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerMergeRangesInCollection\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\CoordinateTest\\:\\:providerCoordinateIsRange\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CoordinateTest.php - - - - message: "#^Parameter \\#1 \\$string of function strlen expects string, PhpOffice\\\\PhpSpreadsheet\\\\RichText\\\\RichText\\|string\\|null given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/DataTypeTest.php - - message: "#^Cannot call method hasValidValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 9 @@ -15935,41 +11260,16 @@ parameters: count: 8 path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\DefaultValueBinderTest\\:\\:createCellStub\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\DefaultValueBinderTest\\:\\:binderProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\DefaultValueBinderTest\\:\\:providerDataTypeForValue\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php - - - - message: "#^Parameter \\#1 \\$pUrl of class PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Hyperlink constructor expects string, null given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Cell/HyperlinkTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Cell\\\\ValueBinderWithOverriddenDataTypeForValue\\:\\:\\$called has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php - - - - message: "#^Parameter \\#1 \\$overlay of method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:setOverlay\\(\\) expects bool, string given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Chart/LegendTest.php - - message: "#^Parameter \\#2 \\$cell of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:add\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + - + message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) with arguments PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, null and 'should get exact…' will always evaluate to false\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Collection/CellsTest.php + - message: "#^Cannot call method getParent\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -15995,101 +11295,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:\\$errorMessage has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:testExpectedExceptions\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:testExpectedExceptions\\(\\) has parameter \\$actual with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:testExpectedExceptions\\(\\) has parameter \\$expected with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has parameter \\$actual with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has parameter \\$delta with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:adjustDelta\\(\\) has parameter \\$expected with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has parameter \\$actual with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has parameter \\$delta with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:assertComplexEquals\\(\\) has parameter \\$expected with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Result of \\|\\| is always false\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Custom\\\\ComplexAssert\\:\\:getErrorMessage\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Custom/ComplexAssert.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedRange\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedFormula\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DefinedNameFormulaTest\\:\\:providerRangeOrFormula\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/DefinedNameTest.php - - - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 20 - path: tests/PhpSpreadsheetTests/DefinedNameTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 14 @@ -16100,86 +11305,11 @@ parameters: count: 6 path: tests/PhpSpreadsheetTests/DefinedNameTest.php - - - message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/DefinedNameTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:\\$properties has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:providerCreationTime\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:providerModifiedTime\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:testSetCustomProperties\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Document\\\\PropertiesTest\\:\\:providerCustomProperties\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Document/PropertiesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:testGenerateFunctionListByName\\(\\) has parameter \\$phpSpreadsheetFunctions with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:testGenerateFunctionListByCategory\\(\\) has parameter \\$phpSpreadsheetFunctions with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:providerGenerateFunctionListByName\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\DocumentGeneratorTest\\:\\:providerGenerateFunctionListByCategory\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/DocumentGeneratorTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ActiveSheetTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ColumnWidthTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ColumnWidthTest\\:\\:testReadColumnWidth\\(\\) has parameter \\$format with no typehint specified\\.$#" count: 1 @@ -16195,11 +11325,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\CommentsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\CommentsTest\\:\\:testComments\\(\\) has parameter \\$format with no typehint specified\\.$#" count: 1 @@ -16210,11 +11335,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ConditionalStopIfTrueTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php - - message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:addCondition\\(\\) expects string, float given\\.$#" count: 2 @@ -16255,11 +11375,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\EnclosureTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -16270,61 +11385,16 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\FreezePaneTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/FreezePaneTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\MergedCellsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/MergedCellsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\PrintAreaTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php - - message: "#^Cannot call method getPageSetup\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 5 path: tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadBlankCellsTest\\:\\:providerSheetFormat\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 3 path: tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadFilterTest\\:\\:providerCellsValues\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadFilterTest\\:\\:testXlsxLoadWithoutReadFilter\\(\\) has parameter \\$arrayData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ReadFilterTest\\:\\:testXlsxLoadWithReadFilter\\(\\) has parameter \\$arrayData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\SelectedCellsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/SelectedCellsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\StreamTest\\:\\:providerFormats\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/StreamTest.php - - message: "#^Cannot access offset 'size' on array\\(0 \\=\\> int, 1 \\=\\> int, 2 \\=\\> int, 3 \\=\\> int, 4 \\=\\> int, 5 \\=\\> int, 6 \\=\\> int, 7 \\=\\> int, \\.\\.\\.\\)\\|false\\.$#" count: 2 @@ -16332,7 +11402,7 @@ parameters: - message: "#^Parameter \\#1 \\$fp of function fstat expects resource, resource\\|false given\\.$#" - count: 2 + count: 1 path: tests/PhpSpreadsheetTests/Functional/StreamTest.php - @@ -16340,21 +11410,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/StreamTest.php - - - message: "#^Parameter \\#1 \\$fp of function ftell expects resource, resource\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/StreamTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\TypeAttributePreservationTest\\:\\:providerFormulae\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\TypeAttributePreservationTest\\:\\:testFormulae\\(\\) has parameter \\$values with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -16375,41 +11430,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\WorkbookViewAttributesTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/WorkbookViewAttributesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Helper\\\\HtmlTest\\:\\:providerUtf8EncodingSupport\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Helper/HtmlTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Helper\\\\SampleTest\\:\\:providerSample\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Helper/SampleTest.php - - message: "#^Parameter \\#1 \\$expected of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) expects class\\-string\\, string given\\.$#" count: 3 path: tests/PhpSpreadsheetTests/IOFactoryTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\IOFactoryTest\\:\\:providerCreateWriter\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/IOFactoryTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\IOFactoryTest\\:\\:providerCreateReader\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/IOFactoryTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\IOFactoryTest\\:\\:providerIdentify\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/IOFactoryTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\NamedFormula\\|null\\.$#" count: 5 @@ -16420,21 +11445,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/NamedRangeTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:\\$startRow has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:\\$endRow has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:\\$filterType has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousFilter\\:\\:setFilterType\\(\\) has parameter \\$type with no typehint specified\\.$#" count: 1 @@ -16460,11 +11470,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvContiguousTest\\:\\:\\$inputFileName has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 3 @@ -16475,36 +11480,16 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php + - + message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNull\\(\\) with string will always evaluate to false\\.$#" + count: 1 + path: tests/PhpSpreadsheetTests/Reader/CsvTest.php + - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 13 path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerDelimiterDetection\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerCanLoad\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerEncodings\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerEscapes\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\CsvTest\\:\\:providerGuessEncoding\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 10 @@ -16525,66 +11510,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerBorderStyle\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerFillType\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerHorizontal\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerUnderline\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerVertical\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\GnumericStylesTest\\:\\:providerDataType\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericStylesTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Gnumeric\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/PageSetupTest.php - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 6 path: tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Html\\\\HtmlBorderTest\\:\\:providerBorderStyle\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php - - - - message: "#^Parameter \\#1 \\$file of function file_put_contents expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Html\\\\HtmlHelper\\:\\:createHtml\\(\\) should return string but returns string\\|false\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 7 @@ -16610,11 +11540,6 @@ parameters: count: 6 path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Html\\\\HtmlTest\\:\\:providerCanReadVerySmallFile\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 16 @@ -16635,16 +11560,6 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\OdsTest\\:\\:\\$timeZone has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - - - message: "#^Negated boolean expression is always false\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 16 @@ -16675,36 +11590,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupBug1772Test\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupBug1772Test\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupBug1772Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Ods\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/PageSetupTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:testValidXML\\(\\) has parameter \\$libxmlDisableEntityLoader with no typehint specified\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:providerValidXML\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php - - message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" count: 3 @@ -16715,26 +11605,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:providerInvalidXML\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Security\\\\XmlScannerTest\\:\\:providerValidXMLForCallback\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\SlkTest\\:\\:\\$testbook has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/SlkTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\SlkTest\\:\\:\\$filename has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/SlkTest.php - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 52 @@ -16750,16 +11620,6 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Reader/SlkTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xls\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xls\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xls/PageSetupTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -16795,11 +11655,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\AutoFilterTest\\:\\:loadDataProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php - - message: "#^Function PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\getTitleText\\(\\) has no return typehint specified\\.$#" count: 1 @@ -16810,21 +11665,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php - - message: "#^Cannot call method setMinimumConditionalFormatValueObject\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" count: 1 @@ -16865,31 +11705,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Reader/Xlsx/NamedRangeTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xlsx\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/PageSetupTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php - - message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 1 @@ -16920,41 +11735,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\XlsxTest\\:\\:testStripsWhiteSpaceFromStyleString\\(\\) has parameter \\$string with no typehint specified\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\XlsxTest\\:\\:providerStripsWhiteSpaceFromStyleString\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\PageSetupTest\\:\\:pageSetupAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\PageSetupTest\\:\\:pageMarginAssertions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/PageSetupTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 11 @@ -16975,36 +11760,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlOddTest\\:\\:\\$filename has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php - - - - message: "#^Parameter \\#1 \\$file of function file_put_contents expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xml\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlStyleCoverageTest\\:\\:providerBorderStyle\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlStyleCoverageTest\\:\\:providerFillType\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlStyleCoverageTest.php - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 70 @@ -17015,11 +11775,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlTest\\:\\:providerInvalidSimpleXML\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - message: "#^Argument of an invalid type array\\\\|false supplied for foreach, only iterables are supported\\.$#" count: 1 @@ -17041,77 +11796,7 @@ parameters: path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\ReferenceHelperTest\\:\\:providerFormulaUpdates\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/ReferenceHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\ReferenceHelperTest\\:\\:providerMultipleWorksheetFormulaUpdates\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/ReferenceHelperTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\CodePageTest\\:\\:providerCodePage\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/CodePageTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:\\$excelCalendar has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:\\$dttimezone has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeExcelToTimestamp1900\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeTimestampToExcel1900\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeDateTimeToExcel\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:testDateTimeFormattedPHPToExcel1900\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeFormattedPHPToExcel1900\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeExcelToTimestamp1904\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeTimestampToExcel1904\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:testIsDateTimeFormatCode\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerIsDateTimeFormatCode\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\DateTest\\:\\:providerDateTimeExcelToTimestamp1900Timezone\\(\\) has no return typehint specified\\.$#" + message: "#^Parameter \\#1 \\$timeZone of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:setDefaultTimezone\\(\\) expects DateTimeZone\\|string, DateTimeZone\\|null given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Shared/DateTest.php @@ -17120,63 +11805,13 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\FontTest\\:\\:providerFontSizeToPixels\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/FontTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\FontTest\\:\\:providerInchSizeToPixels\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/FontTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\FontTest\\:\\:providerCentimeterSizeToPixels\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/FontTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\PasswordHasherTest\\:\\:testHashPassword\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\PasswordHasherTest\\:\\:providerHashPassword\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\StringHelperTest\\:\\:\\$currencyCode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\StringHelperTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\StringHelperTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:setCurrencyCode\\(\\) expects string, null given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Shared/StringHelperTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\TimeZoneTest\\:\\:\\$tztimezone has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\TimeZoneTest\\:\\:\\$dttimezone has no typehint specified\\.$#" + message: "#^Parameter \\#1 \\$timeZone of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:setDefaultTimezone\\(\\) expects DateTimeZone\\|string, DateTimeZone\\|null given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php @@ -17190,21 +11825,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\Trend\\\\ExponentialBestFitTest\\:\\:providerExponentialBestFit\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Shared\\\\Trend\\\\LinearBestFitTest\\:\\:providerLinearBestFit\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\SpreadsheetTest\\:\\:dataProviderForSheetNames\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/SpreadsheetTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\SpreadsheetTest\\:\\:testGetSheetByName\\(\\) has parameter \\$index with no typehint specified\\.$#" count: 1 @@ -17250,46 +11870,6 @@ parameters: count: 65 path: tests/PhpSpreadsheetTests/Style/BorderTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testGetRed\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorGetRed\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testGetGreen\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorGetGreen\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testGetBlue\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorGetBlue\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:testChangeBrightness\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\ColorTest\\:\\:providerColorChangeBrightness\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/ColorTest.php - - message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:addCondition\\(\\) expects string, float given\\.$#" count: 2 @@ -17340,86 +11920,26 @@ parameters: count: 3 path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:\\$currencyCode has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:\\$decimalSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:\\$thousandsSeparator has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:testFormatValueWithMask\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:providerNumberFormat\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:testFormatValueWithMaskDate\\(\\) has parameter \\$args with no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Style\\\\NumberFormatTest\\:\\:providerNumberFormatDates\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/NumberFormatTest.php - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 5 path: tests/PhpSpreadsheetTests/Style/StyleTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\Column\\\\RuleTest\\:\\:\\$testAutoFilterRuleObject has no typehint specified\\.$#" + message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:setValue\\(\\) expects array\\\\|string, int given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\Column\\\\RuleTest\\:\\:\\$mockAutoFilterColumnObject has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\ColumnTest\\:\\:\\$testInitialColumn has no typehint specified\\.$#" - count: 1 + message: "#^Parameter \\#1 \\$attributes of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttributes\\(\\) expects array\\, array\\ given\\.$#" + count: 3 path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\ColumnTest\\:\\:\\$testAutoFilterColumnObject has no typehint specified\\.$#" + message: "#^Parameter \\#2 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\:\\:setAttribute\\(\\) expects string, int given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilter\\\\ColumnTest\\:\\:\\$mockAutoFilterObject has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilterTest\\:\\:\\$testInitialRange has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilterTest\\:\\:\\$mockWorksheetObject has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\AutoFilterTest\\:\\:\\$cellCollection has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php - - message: "#^Parameter \\#1 \\$pColumn of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\:\\:setColumn\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\|string, float given\\.$#" count: 1 @@ -17430,46 +11950,6 @@ parameters: count: 4 path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIterator2Test\\:\\:providerExistingCell\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIterator2Test\\:\\:providerEmptyColumn\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnCellIteratorTest\\:\\:\\$mockCell has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnIteratorTest\\:\\:\\$mockColumn has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\ColumnTest\\:\\:\\$mockColumn has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php - - message: "#^Parameter \\#1 \\$im of function imagecolorallocate expects resource, resource\\|false given\\.$#" count: 1 @@ -17490,95 +11970,30 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\PageMarginsTest\\:\\:providerPointsAndInches\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\PageMarginsTest\\:\\:providerCentimetersAndInches\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\PageMarginsTest\\:\\:providerMillimetersAndInches\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/PageMarginsTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 4 path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIterator2Test\\:\\:providerExistingCell\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php - - message: "#^Parameter \\#2 \\$rowIndex of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowCellIterator constructor expects int, string given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIterator2Test\\:\\:providerEmptyRow\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowCellIteratorTest\\:\\:\\$mockCell has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowIteratorTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowIteratorTest\\:\\:\\$mockRow has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowTest\\:\\:\\$mockWorksheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\RowTest\\:\\:\\$mockRow has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/RowTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetNamedRangesTest\\:\\:\\$spreadsheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:setTitleInvalidProvider\\(\\) has no return typehint specified\\.$#" + message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:setCodeNameInvalidProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:extractSheetTitleProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php + message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" @@ -17590,106 +12005,21 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:removeColumnProvider\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveColumn\\(\\) has parameter \\$expectedData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveColumn\\(\\) has parameter \\$initialData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:removeRowsProvider\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveRows\\(\\) has parameter \\$expectedData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Worksheet\\\\WorksheetTest\\:\\:testRemoveRows\\(\\) has parameter \\$initialData with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Csv\\\\CsvEnclosureTest\\:\\:\\$cellValues has no typehint specified\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|false given\\.$#" count: 4 path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 11 path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php - - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php - - - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Csv\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Csv\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -17700,21 +12030,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php - - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php - - message: "#^Parameter \\#1 \\$haystack of function strpos expects string, string\\|false given\\.$#" count: 1 @@ -17740,16 +12055,6 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlCommentsTest\\:\\:\\$spreadsheet has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlCommentsTest\\:\\:providerCommentRichText\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php - - message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" count: 3 @@ -17760,38 +12065,13 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:\\$currency has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:\\$decsep has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:\\$thosep has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:providerNumberFormat\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\HtmlNumberFormatTest\\:\\:providerNumberFormatDates\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\ImagesRootTest\\:\\:\\$curdir has no typehint specified\\.$#" + message: "#^Parameter \\#1 \\$directory of function chdir expects string, string\\|false given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php @@ -17815,101 +12095,16 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/VisibilityTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\XssVulnerabilityTest\\:\\:providerAcceptableMarkupRichText\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Parameter \\#1 \\$filename of function file_get_contents expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\XssVulnerabilityTest\\:\\:providerXssRichText\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringNotContainsString\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Ods\\\\ContentTest\\:\\:\\$samplesPath has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\RetainSelectedCellsTest\\:\\:providerFormats\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\IWriter\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\IReader\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 4 path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:testAddColor\\(\\) has parameter \\$expectedResult with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:testAddColor\\(\\) has parameter \\$testColors with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:providerAddColor\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\WorkbookTest\\:\\:paletteToColor\\(\\) has parameter \\$palette with no value type specified in iterable type array\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xls\\\\XlsGifBmpTest\\:\\:\\$filename has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xls/XlsGifBmpTest.php - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" count: 1 @@ -17920,38 +12115,13 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xlsx\\\\FloatsRetainedTest\\:\\:providerIntyFloatsRetainedByWriter\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xlsx\\\\LocaleFloatsTest\\:\\:\\$localeAdjusted has no typehint specified\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Xlsx\\\\LocaleFloatsTest\\:\\:\\$currentLocale has no typehint specified\\.$#" + message: "#^Parameter \\#2 \\$locale of function setlocale expects string\\|null, string\\|false given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php @@ -17970,21 +12140,6 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -18000,46 +12155,16 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - message: "#^Parameter \\#1 \\$filename of method ZipArchive\\:\\:open\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - - message: "#^Parameter \\#1 \\$filename of method ZipArchive\\:\\:open\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\:\\:load\\(\\) expects string, string\\|false given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - message: "#^Cannot call method getDrawingCollection\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 4 @@ -18060,31 +12185,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - - message: "#^Parameter \\#1 \\$pFilename of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\:\\:save\\(\\) expects resource\\|string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - - - message: "#^Parameter \\#1 \\$filename of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertFileExists\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - - - message: "#^Parameter \\#1 \\$filename of method ZipArchive\\:\\:open\\(\\) expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - - - message: "#^Parameter \\#1 \\$filename of function unlink expects string, string\\|false given\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - - - message: "#^Parameter \\#2 \\$haystack of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertStringContainsString\\(\\) expects string, string\\|false given\\.$#" - count: 8 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - message: "#^Parameter \\#1 \\$data of function simplexml_load_string expects string, string\\|false given\\.$#" count: 2 @@ -18110,33 +12210,3 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php - - - message: "#^Function calculationTestDataGenerator\\(\\) has no return typehint specified\\.$#" - count: 1 - path: tests/data/Calculation/Calculation.php - - - - message: "#^Comparison operation \"\\>\" between 1 and 0 is always true\\.$#" - count: 4 - path: tests/data/Calculation/Logical/XOR.php - - - - message: "#^Comparison operation \"\\>\" between 2 and 0 is always true\\.$#" - count: 4 - path: tests/data/Calculation/Logical/XOR.php - - - - message: "#^Comparison operation \"\\>\" between 0 and 1 is always false\\.$#" - count: 5 - path: tests/data/Calculation/Logical/XOR.php - - - - message: "#^Comparison operation \"\\>\" between 0 and 2 is always false\\.$#" - count: 2 - path: tests/data/Calculation/Logical/XOR.php - - - - message: "#^Comparison operation \"\\>\" between 3 and 0 is always true\\.$#" - count: 1 - path: tests/data/Calculation/Logical/XOR.php - diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f39ce395..dd39aa34 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,5 +1,7 @@ includes: - - phpstan-baseline.neon + - phpstan-baseline.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon parameters: level: max @@ -8,11 +10,15 @@ parameters: - tests/ parallel: processTimeout: 300.0 + checkMissingIterableValueType: false ignoreErrors: - '~^Class GdImage not found\.$~' - '~^Return typehint of method .* has invalid type GdImage\.$~' - '~^Property .* has unknown class GdImage as its type\.$~' - '~^Parameter .* of method .* has invalid typehint type GdImage\.$~' + # Accept a bit anything for assert methods + - '~^Parameter \#2 .* of static method PHPUnit\\Framework\\Assert\:\:assert\w+\(\) expects .*, .* given\.$~' + - '~^Method PhpOffice\\PhpSpreadsheetTests\\.*\:\:test.*\(\) has parameter \$args with no typehint specified\.$~' # Ignore all JpGraph issues - '~^Constant (MARK_CIRCLE|MARK_CROSS|MARK_DIAMOND|MARK_DTRIANGLE|MARK_FILLEDCIRCLE|MARK_SQUARE|MARK_STAR|MARK_UTRIANGLE|MARK_X|SIDE_RIGHT) not found\.$~' diff --git a/samples/Reader/20_Reader_worksheet_hyperlink_image.php b/samples/Reader/20_Reader_worksheet_hyperlink_image.php index 9dad4b6c..19d837a5 100644 --- a/samples/Reader/20_Reader_worksheet_hyperlink_image.php +++ b/samples/Reader/20_Reader_worksheet_hyperlink_image.php @@ -1,5 +1,6 @@ log('Write link: ' . $baseUrl); $drawing->setWorksheet($aSheet); -$filename = tempnam(\PhpOffice\PhpSpreadsheet\Shared\File::sysGetTempDir(), 'phpspreadsheet-test'); +$filename = File::temporaryFilename(); $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, $inputFileType); $writer->save($filename); diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php index 15811ee5..ea4fe340 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/WeekDay.php @@ -17,7 +17,7 @@ class WeekDay * Excel Function: * WEEKDAY(dateValue[,style]) * - * @param float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer), + * @param null|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer), * PHP DateTime object, or a standard date string * @param int $style A number that determines the type of return value * 1 or omitted Numbers 1 (Sunday) through 7 (Saturday). diff --git a/src/PhpSpreadsheet/Chart/Legend.php b/src/PhpSpreadsheet/Chart/Legend.php index fc0ed140..2f003cd8 100644 --- a/src/PhpSpreadsheet/Chart/Legend.php +++ b/src/PhpSpreadsheet/Chart/Legend.php @@ -131,18 +131,10 @@ class Legend * Set allow overlay of other elements? * * @param bool $overlay - * - * @return bool */ - public function setOverlay($overlay) + public function setOverlay($overlay): void { - if (!is_bool($overlay)) { - return false; - } - $this->overlay = $overlay; - - return true; } /** diff --git a/src/PhpSpreadsheet/Collection/Cells.php b/src/PhpSpreadsheet/Collection/Cells.php index 7859965b..c5247090 100644 --- a/src/PhpSpreadsheet/Collection/Cells.php +++ b/src/PhpSpreadsheet/Collection/Cells.php @@ -12,7 +12,7 @@ use Psr\SimpleCache\CacheInterface; class Cells { /** - * @var \Psr\SimpleCache\CacheInterface + * @var CacheInterface */ private $cache; @@ -405,7 +405,7 @@ class Cells * @param string $pCoord Coordinate of the cell to update * @param Cell $cell Cell to update * - * @return \PhpOffice\PhpSpreadsheet\Cell\Cell + * @return Cell */ public function add($pCoord, Cell $cell) { @@ -426,7 +426,7 @@ class Cells * * @param string $pCoord Coordinate of the cell * - * @return null|\PhpOffice\PhpSpreadsheet\Cell\Cell Cell that was found, or null if not found + * @return null|Cell Cell that was found, or null if not found */ public function get($pCoord) { diff --git a/src/PhpSpreadsheet/Shared/File.php b/src/PhpSpreadsheet/Shared/File.php index 7525df8a..7991ed45 100644 --- a/src/PhpSpreadsheet/Shared/File.php +++ b/src/PhpSpreadsheet/Shared/File.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared; use InvalidArgumentException; +use PhpOffice\PhpSpreadsheet\Exception; use ZipArchive; class File @@ -124,6 +125,16 @@ class File return realpath(sys_get_temp_dir()); } + public static function temporaryFilename(): string + { + $filename = tempnam(self::sysGetTempDir(), 'phpspreadsheet'); + if ($filename === false) { + throw new Exception('Could not create temporary file'); + } + + return $filename; + } + /** * Assert that given path is an existing file and is readable, otherwise throw exception. * diff --git a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php index f1f0bea2..433d2be5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/CalculationTest.php @@ -10,8 +10,14 @@ use PHPUnit\Framework\TestCase; class CalculationTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; + /** + * @var string + */ private $locale; protected function setUp(): void @@ -47,7 +53,7 @@ class CalculationTest extends TestCase self::assertEquals($expectedResultOpenOffice, $resultOpenOffice, 'should be OpenOffice compatible'); } - public function providerBinaryComparisonOperation() + public function providerBinaryComparisonOperation(): array { return require 'tests/data/CalculationBinaryComparisonOperation.php'; } @@ -64,7 +70,7 @@ class CalculationTest extends TestCase self::assertIsCallable($functionCall); } - public function providerGetFunctions() + public function providerGetFunctions(): array { return Calculation::getInstance()->getFunctions(); } @@ -89,7 +95,7 @@ class CalculationTest extends TestCase self::assertTrue($calculation->setLocale($locale)); } - public function providerCanLoadAllSupportedLocales() + public function providerCanLoadAllSupportedLocales(): array { return [ ['bg'], @@ -118,11 +124,13 @@ class CalculationTest extends TestCase $calculation = Calculation::getInstance(); $tree = $calculation->parseFormula('=_xlfn.ISFORMULA(A1)'); + self::assertIsArray($tree); self::assertCount(3, $tree); $function = $tree[2]; self::assertEquals('Function', $function['type']); $tree = $calculation->parseFormula('=_xlfn.STDEV.S(A1:B2)'); + self::assertIsArray($tree); self::assertCount(5, $tree); $function = $tree[4]; self::assertEquals('Function', $function['type']); @@ -205,6 +213,7 @@ class CalculationTest extends TestCase // Very simple formula $formula = '=IF(A1="please +",B1)'; $tokens = $calculation->parseFormula($formula); + self::assertIsArray($tokens); $foundEqualAssociatedToStoreKey = false; $foundConditionalOnB1 = false; @@ -234,6 +243,7 @@ class CalculationTest extends TestCase // Internal operation $formula = '=IF(A1="please +",SUM(B1:B3))+IF(A2="please *",PRODUCT(C1:C3), C1)'; $tokens = $calculation->parseFormula($formula); + self::assertIsArray($tokens); $plusGotTagged = false; $productFunctionCorrectlyTagged = false; @@ -263,6 +273,7 @@ class CalculationTest extends TestCase $formula = '=IF(A1="please +",SUM(B1:B3),1+IF(NOT(A2="please *"),C2-C1,PRODUCT(C1:C3)))'; $tokens = $calculation->parseFormula($formula); + self::assertIsArray($tokens); $plusCorrectlyTagged = false; $productFunctionCorrectlyTagged = false; @@ -307,6 +318,8 @@ class CalculationTest extends TestCase $formula = '=IF(A1="flag",IF(A2<10, 0) + IF(A3<10000, 0))'; $tokens = $calculation->parseFormula($formula); + self::assertIsArray($tokens); + $properlyTaggedPlus = false; foreach ($tokens as $token) { $isPlus = $token['value'] === '+'; @@ -367,7 +380,7 @@ class CalculationTest extends TestCase self::assertEquals($expectedResult, $calculated); } - public function dataProviderBranchPruningFullExecution() + public function dataProviderBranchPruningFullExecution(): array { return require 'tests/data/Calculation/Calculation.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php b/tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php index 76886c23..6f97f9c8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/DefinedNameConfusedForCellTest.php @@ -2,20 +2,23 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation; +use PhpOffice\PhpSpreadsheet\IOFactory; +use PhpOffice\PhpSpreadsheet\NamedRange; use PhpOffice\PhpSpreadsheet\Shared\File; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class DefinedNameConfusedForCellTest extends TestCase { public function testDefinedName(): void { - $obj = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); + $obj = new Spreadsheet(); $sheet0 = $obj->setActiveSheetIndex(0); $sheet0->setCellValue('A1', 2); - $obj->addNamedRange(new \PhpOffice\PhpSpreadsheet\NamedRange('A1A', $sheet0, 'A1')); + $obj->addNamedRange(new NamedRange('A1A', $sheet0, 'A1')); $sheet0->setCellValue('B1', '=2*A1A'); - $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($obj, 'Xlsx'); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $writer = IOFactory::createWriter($obj, 'Xlsx'); + $filename = File::temporaryFilename(); $writer->save($filename); self::assertTrue(true); unlink($filename); diff --git a/tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php b/tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php index 4f1ff397..c27d16af 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php @@ -9,7 +9,10 @@ use PHPUnit\Framework\TestCase; class RangeTest extends TestCase { - protected $spreadSheet; + /** + * @var Spreadsheet + */ + private $spreadSheet; protected function setUp(): void { @@ -40,7 +43,7 @@ class RangeTest extends TestCase self::assertSame($expectedResult, $actualRresult); } - public function providerRangeEvaluation() + public function providerRangeEvaluation(): array { return[ ['=SUM(A1:B3,A1:C2)', 48], @@ -88,7 +91,7 @@ class RangeTest extends TestCase self::assertSame($expectedResult, $sumRresult); } - public function providerNamedRangeEvaluation() + public function providerNamedRangeEvaluation(): array { return[ ['$A$1:$B$3', '$A$1:$C$2', '=SUM(GROUP1,GROUP2)', 48], @@ -123,7 +126,7 @@ class RangeTest extends TestCase self::assertSame($expectedResult, $sumRresult); } - public function providerUTF8NamedRangeEvaluation() + public function providerUTF8NamedRangeEvaluation(): array { return[ [['Γειά', 'σου', 'Κόσμε'], ['$A$1', '$B$1:$B$2', '$C$1:$C$3'], '=SUM(Γειά,σου,Κόσμε)', 26], @@ -151,7 +154,7 @@ class RangeTest extends TestCase self::assertSame($expectedCount, $actualCount); } - public function providerCompositeNamedRangeEvaluation() + public function providerCompositeNamedRangeEvaluation(): array { return[ // Calculation engine doesn't yet handle union ranges with overlap diff --git a/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php b/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php index 9afe5570..27c746b4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php @@ -39,7 +39,7 @@ class FormulaAsStringTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerFunctionsAsString() + public function providerFunctionsAsString(): array { return require 'tests/data/Calculation/FunctionsAsString.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php index 91011504..2d8fb9f9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DAverageTest.php @@ -27,7 +27,7 @@ class DAverageTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DAverageTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Quarter', 'Area', 'Sales Rep.', 'Sales'], @@ -63,7 +63,7 @@ class DAverageTest extends TestCase ]; } - public function providerDAverage() + public function providerDAverage(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php index f5214ed0..2f7cad14 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountATest.php @@ -27,7 +27,7 @@ class DCountATest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DCountATest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DCountATest extends TestCase ]; } - public function providerDCountA() + public function providerDCountA(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php index 11d8adab..3f9d9966 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DCountTest.php @@ -27,7 +27,7 @@ class DCountTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DCountTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DCountTest extends TestCase ]; } - protected function database3() + private function database3(): array { return [ ['Status', 'Value'], @@ -74,7 +74,7 @@ class DCountTest extends TestCase ]; } - public function providerDCount() + public function providerDCount(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php index 3d90ff96..7853e0b6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DGetTest.php @@ -27,7 +27,7 @@ class DGetTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DGetTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Quarter', 'Area', 'Sales Rep.', 'Sales'], @@ -63,7 +63,7 @@ class DGetTest extends TestCase ]; } - public function providerDGet() + public function providerDGet(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php index b0ad59a7..94ac0425 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMaxTest.php @@ -27,7 +27,7 @@ class DMaxTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DMaxTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Quarter', 'Area', 'Sales Rep.', 'Sales'], @@ -63,7 +63,7 @@ class DMaxTest extends TestCase ]; } - public function providerDMax() + public function providerDMax(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php index bfd2af4c..a02ad2e1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DMinTest.php @@ -27,7 +27,7 @@ class DMinTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DMinTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DMinTest extends TestCase ]; } - public function providerDMin() + public function providerDMin(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php index 0fb1bba7..14962558 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DProductTest.php @@ -28,7 +28,7 @@ class DProductTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -41,7 +41,7 @@ class DProductTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Date', 'Test', 'Score'], @@ -60,7 +60,7 @@ class DProductTest extends TestCase ]; } - public function providerDProduct() + public function providerDProduct(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php index 210325d5..669a694b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevPTest.php @@ -27,7 +27,7 @@ class DStDevPTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DStDevPTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DStDevPTest extends TestCase ]; } - public function providerDStDevP() + public function providerDStDevP(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php index 71bbcd2a..a7975a11 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DStDevTest.php @@ -27,7 +27,7 @@ class DStDevTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DStDevTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DStDevTest extends TestCase ]; } - public function providerDStDev() + public function providerDStDev(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php index 5c270fd2..55edffe0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DSumTest.php @@ -27,7 +27,7 @@ class DSumTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DSumTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Quarter', 'Area', 'Sales Rep.', 'Sales'], @@ -63,7 +63,7 @@ class DSumTest extends TestCase ]; } - public function providerDSum() + public function providerDSum(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php index 0436ea67..60612db5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarPTest.php @@ -27,7 +27,7 @@ class DVarPTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DVarPTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DVarPTest extends TestCase ]; } - public function providerDVarP() + public function providerDVarP(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php index 467db2f2..0015b7fb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Database/DVarTest.php @@ -27,7 +27,7 @@ class DVarTest extends TestCase self::assertSame($expectedResult, $result); } - protected function database1() + private function database1(): array { return [ ['Tree', 'Height', 'Age', 'Yield', 'Profit'], @@ -40,7 +40,7 @@ class DVarTest extends TestCase ]; } - protected function database2() + private function database2(): array { return [ ['Name', 'Gender', 'Age', 'Subject', 'Score'], @@ -59,7 +59,7 @@ class DVarTest extends TestCase ]; } - public function providerDVar() + public function providerDVar(): array { return [ [ diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php index c56c7431..414670c4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/AllSetupTeardown.php @@ -6,18 +6,34 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PHPUnit\Framework\TestCase; class AllSetupTeardown extends TestCase { - protected $compatibilityMode; + /** + * @var string + */ + private $compatibilityMode; - protected $excelCalendar; + /** + * @var int + */ + private $excelCalendar; - protected $returnDateType; + /** + * @var string + */ + private $returnDateType; + /** + * @var Spreadsheet + */ protected $spreadsheet; + /** + * @var Worksheet + */ protected $sheet; protected function setUp(): void @@ -35,8 +51,6 @@ class AllSetupTeardown extends TestCase Functions::setCompatibilityMode($this->compatibilityMode); Functions::setReturnDateType($this->returnDateType); $this->spreadsheet->disconnectWorksheets(); - $this->spreadsheet = null; - $this->sheet = null; } protected static function setMac1904(): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php index 6c394087..3aa9446d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php @@ -18,7 +18,7 @@ class DateDifTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerDATEDIF() + public function providerDATEDIF(): array { return require 'tests/data/Calculation/DateTime/DATEDIF.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php index 354e6f3b..d790777b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php @@ -20,7 +20,7 @@ class DateTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerDATE() + public function providerDATE(): array { return require 'tests/data/Calculation/DateTime/DATE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php index fc432bbe..2d422e0a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php @@ -37,7 +37,7 @@ class DateValueTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDATEVALUE() + public function providerDATEVALUE(): array { return require 'tests/data/Calculation/DateTime/DATEVALUE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php index e50475cf..dc8adf11 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php @@ -18,7 +18,7 @@ class DayTest extends AllSetupTeardown self::assertSame($expectedResultExcel, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerDAY() + public function providerDAY(): array { return require 'tests/data/Calculation/DateTime/DAY.php'; } @@ -37,7 +37,7 @@ class DayTest extends AllSetupTeardown self::assertSame($expectedResultOpenOffice, $sheet->getCell('A2')->getCalculatedValue()); } - public function providerDAYOpenOffice() + public function providerDAYOpenOffice(): array { return require 'tests/data/Calculation/DateTime/DAYOpenOffice.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php index 5d6ba29e..bd3a0283 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php @@ -19,7 +19,7 @@ class Days360Test extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerDAYS360() + public function providerDAYS360(): array { return require 'tests/data/Calculation/DateTime/DAYS360.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php index 8b3ea392..8c65622a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php @@ -24,7 +24,7 @@ class DaysTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerDAYS() + public function providerDAYS(): array { return require 'tests/data/Calculation/DateTime/DAYS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php index 384e1aec..efb34d0d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php @@ -20,7 +20,7 @@ class EDateTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerEDATE() + public function providerEDATE(): array { return require 'tests/data/Calculation/DateTime/EDATE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php index 1af81c9f..6db76f58 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php @@ -20,7 +20,7 @@ class EoMonthTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerEOMONTH() + public function providerEOMONTH(): array { return require 'tests/data/Calculation/DateTime/EOMONTH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php index 99544b5a..93afbb5d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php @@ -18,7 +18,7 @@ class HourTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerHOUR() + public function providerHOUR(): array { return require 'tests/data/Calculation/DateTime/HOUR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php index b27ca7d5..6be2e1af 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php @@ -19,7 +19,7 @@ class IsoWeekNumTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerISOWEEKNUM() + public function providerISOWEEKNUM(): array { return require 'tests/data/Calculation/DateTime/ISOWEEKNUM.php'; } @@ -40,7 +40,7 @@ class IsoWeekNumTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerISOWEEKNUM1904() + public function providerISOWEEKNUM1904(): array { return require 'tests/data/Calculation/DateTime/ISOWEEKNUM1904.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php index cbc2a1a4..57d7a77e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php @@ -18,7 +18,7 @@ class MinuteTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerMINUTE() + public function providerMINUTE(): array { return require 'tests/data/Calculation/DateTime/MINUTE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php index a9f70229..ed09a993 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php @@ -18,7 +18,7 @@ class MonthTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerMONTH() + public function providerMONTH(): array { return require 'tests/data/Calculation/DateTime/MONTH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php index 568c661c..b121f7bf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php @@ -45,7 +45,7 @@ class NetworkDaysTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('B1')->getCalculatedValue()); } - public function providerNETWORKDAYS() + public function providerNETWORKDAYS(): array { return require 'tests/data/Calculation/DateTime/NETWORKDAYS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php index 03cef8bc..6c264a57 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php @@ -18,7 +18,7 @@ class SecondTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerSECOND() + public function providerSECOND(): array { return require 'tests/data/Calculation/DateTime/SECOND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php index f33b5aac..d6910024 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php @@ -22,7 +22,7 @@ class TimeTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $sheet->getCell('A1')->getCalculatedValue(), 1E-8); } - public function providerTIME() + public function providerTIME(): array { return require 'tests/data/Calculation/DateTime/TIME.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php index eceb0519..ac4d3dbd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php @@ -22,7 +22,7 @@ class TimeValueTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerTIMEVALUE() + public function providerTIMEVALUE(): array { return require 'tests/data/Calculation/DateTime/TIMEVALUE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php index 2e52a5d7..c95ce9cc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php @@ -20,7 +20,7 @@ class WeekDayTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerWEEKDAY() + public function providerWEEKDAY(): array { return require 'tests/data/Calculation/DateTime/WEEKDAY.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php index c3e785f3..cf8ac65b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php @@ -18,7 +18,7 @@ class WeekNumTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerWEEKNUM() + public function providerWEEKNUM(): array { return require 'tests/data/Calculation/DateTime/WEEKNUM.php'; } @@ -38,7 +38,7 @@ class WeekNumTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerWEEKNUM1904() + public function providerWEEKNUM1904(): array { return require 'tests/data/Calculation/DateTime/WEEKNUM1904.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php index ec2a5402..80829699 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php @@ -45,7 +45,7 @@ class WorkDayTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('B1')->getCalculatedValue()); } - public function providerWORKDAY() + public function providerWORKDAY(): array { return require 'tests/data/Calculation/DateTime/WORKDAY.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php index e6ac823a..e16ce697 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php @@ -37,7 +37,7 @@ class YearFracTest extends AllSetupTeardown self::assertEqualswithDelta($expectedResult, $sheet->getCell('B1')->getCalculatedValue(), 1E-6); } - public function providerYEARFRAC() + public function providerYEARFRAC(): array { return require 'tests/data/Calculation/DateTime/YEARFRAC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php index 7942f06c..74b3bed0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php @@ -18,7 +18,7 @@ class YearTest extends AllSetupTeardown self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerYEAR() + public function providerYEAR(): array { return require 'tests/data/Calculation/DateTime/YEAR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php index 5b6ba045..d24a0208 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselITest.php @@ -26,7 +26,7 @@ class BesselITest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::BESSEL_PRECISION); } - public function providerBESSELI() + public function providerBESSELI(): array { return require 'tests/data/Calculation/Engineering/BESSELI.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php index d10f028f..325a0d64 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselJTest.php @@ -26,7 +26,7 @@ class BesselJTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::BESSEL_PRECISION); } - public function providerBESSEJ() + public function providerBESSEJ(): array { return require 'tests/data/Calculation/Engineering/BESSELJ.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php index 23ad3539..51725d38 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselKTest.php @@ -26,7 +26,7 @@ class BesselKTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::BESSEL_PRECISION); } - public function providerBESSELK() + public function providerBESSELK(): array { return require 'tests/data/Calculation/Engineering/BESSELK.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php index 4422ad50..1e8d863f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BesselYTest.php @@ -26,7 +26,7 @@ class BesselYTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::BESSEL_PRECISION); } - public function providerBESSELY() + public function providerBESSELY(): array { return require 'tests/data/Calculation/Engineering/BESSELY.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php index bcefa891..c0923d1a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Bin2DecTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Bin2DecTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBIN2DEC() + public function providerBIN2DEC(): array { return require 'tests/data/Calculation/Engineering/BIN2DEC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php index 2cbea34a..c95c375d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Bin2HexTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Bin2HexTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBIN2HEX() + public function providerBIN2HEX(): array { return require 'tests/data/Calculation/Engineering/BIN2HEX.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php index e76778f2..ee54063c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Bin2OctTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Bin2OctTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBIN2OCT() + public function providerBIN2OCT(): array { return require 'tests/data/Calculation/Engineering/BIN2OCT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php index 01d006c4..23682908 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php @@ -26,7 +26,7 @@ class BitAndTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBITAND() + public function providerBITAND(): array { return require 'tests/data/Calculation/Engineering/BITAND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php index f1a716ef..ee408497 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php @@ -26,7 +26,7 @@ class BitLShiftTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBITLSHIFT() + public function providerBITLSHIFT(): array { return require 'tests/data/Calculation/Engineering/BITLSHIFT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php index fce287d9..3cc1f4bc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php @@ -26,7 +26,7 @@ class BitOrTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBITOR() + public function providerBITOR(): array { return require 'tests/data/Calculation/Engineering/BITOR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php index 40b929e3..f58d6149 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php @@ -26,7 +26,7 @@ class BitRShiftTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBITRSHIFT() + public function providerBITRSHIFT(): array { return require 'tests/data/Calculation/Engineering/BITRSHIFT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php index 847e44a2..4fa302af 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php @@ -26,7 +26,7 @@ class BitXorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBITXOR() + public function providerBITXOR(): array { return require 'tests/data/Calculation/Engineering/BITXOR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php index 4b857e2d..f60315dc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ComplexTest.php @@ -24,7 +24,7 @@ class ComplexTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCOMPLEX() + public function providerCOMPLEX(): array { return require 'tests/data/Calculation/Engineering/COMPLEX.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php index cf43c759..87198edb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ConvertUoMTest.php @@ -54,7 +54,7 @@ class ConvertUoMTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCONVERTUOM() + public function providerCONVERTUOM(): array { return require 'tests/data/Calculation/Engineering/CONVERTUOM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php index 420af2c5..dfed3478 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Dec2BinTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Dec2BinTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDEC2BIN() + public function providerDEC2BIN(): array { return require 'tests/data/Calculation/Engineering/DEC2BIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php index fcd9c52a..ebe49464 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php @@ -10,6 +10,9 @@ use PHPUnit\Framework\TestCase; class Dec2HexTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -41,7 +44,7 @@ class Dec2HexTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDEC2HEX() + public function providerDEC2HEX(): array { return require 'tests/data/Calculation/Engineering/DEC2HEX.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php index 19846a3b..093f17bc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Dec2OctTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Dec2OctTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDEC2OCT() + public function providerDEC2OCT(): array { return require 'tests/data/Calculation/Engineering/DEC2OCT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php index a93d2ea6..749b33c2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/DeltaTest.php @@ -24,7 +24,7 @@ class DeltaTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDELTA() + public function providerDELTA(): array { return require 'tests/data/Calculation/Engineering/DELTA.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php index 09bf448e..45d5b4c8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfCTest.php @@ -27,7 +27,7 @@ class ErfCTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::ERF_PRECISION); } - public function providerERFC() + public function providerERFC(): array { return require 'tests/data/Calculation/Engineering/ERFC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php index eb26ae98..952b2560 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfPreciseTest.php @@ -27,7 +27,7 @@ class ErfPreciseTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::ERF_PRECISION); } - public function providerERFPRECISE() + public function providerERFPRECISE(): array { return require 'tests/data/Calculation/Engineering/ERFPRECISE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php index 8201edbc..9866024f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ErfTest.php @@ -27,7 +27,7 @@ class ErfTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::ERF_PRECISION); } - public function providerERF() + public function providerERF(): array { return require 'tests/data/Calculation/Engineering/ERF.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php index 370c1a82..07e3a48c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/GeStepTest.php @@ -24,7 +24,7 @@ class GeStepTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerGESTEP() + public function providerGESTEP(): array { return require 'tests/data/Calculation/Engineering/GESTEP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php index 45973004..ad76716c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Hex2BinTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Hex2BinTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerHEX2BIN() + public function providerHEX2BIN(): array { return require 'tests/data/Calculation/Engineering/HEX2BIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php index 264ec3e3..806ba44d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Hex2DecTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Hex2DecTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerHEX2DEC() + public function providerHEX2DEC(): array { return require 'tests/data/Calculation/Engineering/HEX2DEC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php index 15220178..41f1a8f7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Hex2OctTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Hex2OctTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerHEX2OCT() + public function providerHEX2OCT(): array { return require 'tests/data/Calculation/Engineering/HEX2OCT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImAbsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImAbsTest.php index 1f1ee9dd..367cfb33 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImAbsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImAbsTest.php @@ -27,7 +27,7 @@ class ImAbsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::COMPLEX_PRECISION); } - public function providerIMABS() + public function providerIMABS(): array { return require 'tests/data/Calculation/Engineering/IMABS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImArgumentTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImArgumentTest.php index 6f1a6485..9ff8209f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImArgumentTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImArgumentTest.php @@ -27,7 +27,7 @@ class ImArgumentTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::COMPLEX_PRECISION); } - public function providerIMARGUMENT() + public function providerIMARGUMENT(): array { return require 'tests/data/Calculation/Engineering/IMARGUMENT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php index af96c18e..d952f5df 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImConjugateTest.php @@ -14,7 +14,7 @@ class ImConjugateTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImConjugateTest extends TestCase ); } - public function providerIMCONJUGATE() + public function providerIMCONJUGATE(): array { return require 'tests/data/Calculation/Engineering/IMCONJUGATE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php index c00bafda..b6cb8dc2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCosTest.php @@ -14,7 +14,7 @@ class ImCosTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImCosTest extends TestCase ); } - public function providerIMCOS() + public function providerIMCOS(): array { return require 'tests/data/Calculation/Engineering/IMCOS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php index 6f84217a..0d544084 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCoshTest.php @@ -14,7 +14,7 @@ class ImCoshTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImCoshTest extends TestCase ); } - public function providerIMCOSH() + public function providerIMCOSH(): array { return require 'tests/data/Calculation/Engineering/IMCOSH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php index cbadfd8a..69bd02ff 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCotTest.php @@ -14,7 +14,7 @@ class ImCotTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImCotTest extends TestCase ); } - public function providerIMCOT() + public function providerIMCOT(): array { return require 'tests/data/Calculation/Engineering/IMCOT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php index 65782e32..51843f89 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCscTest.php @@ -14,7 +14,7 @@ class ImCscTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImCscTest extends TestCase ); } - public function providerIMCSC() + public function providerIMCSC(): array { return require 'tests/data/Calculation/Engineering/IMCSC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php index ef1c06ea..d2d7511d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImCschTest.php @@ -14,7 +14,7 @@ class ImCschTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImCschTest extends TestCase ); } - public function providerIMCSCH() + public function providerIMCSCH(): array { return require 'tests/data/Calculation/Engineering/IMCSCH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php index 0943f408..652f5ca2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImDivTest.php @@ -14,7 +14,7 @@ class ImDivTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -36,7 +36,7 @@ class ImDivTest extends TestCase ); } - public function providerIMDIV() + public function providerIMDIV(): array { return require 'tests/data/Calculation/Engineering/IMDIV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php index 5f5edfd3..d7be573f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImExpTest.php @@ -14,7 +14,7 @@ class ImExpTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImExpTest extends TestCase ); } - public function providerIMEXP() + public function providerIMEXP(): array { return require 'tests/data/Calculation/Engineering/IMEXP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php index 36ca116a..4566607b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLnTest.php @@ -14,7 +14,7 @@ class ImLnTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImLnTest extends TestCase ); } - public function providerIMLN() + public function providerIMLN(): array { return require 'tests/data/Calculation/Engineering/IMLN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php index 9a37d85c..0d818686 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog10Test.php @@ -14,7 +14,7 @@ class ImLog10Test extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImLog10Test extends TestCase ); } - public function providerIMLOG10() + public function providerIMLOG10(): array { return require 'tests/data/Calculation/Engineering/IMLOG10.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php index f0d853ba..02583448 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImLog2Test.php @@ -14,7 +14,7 @@ class ImLog2Test extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImLog2Test extends TestCase ); } - public function providerIMLOG2() + public function providerIMLOG2(): array { return require 'tests/data/Calculation/Engineering/IMLOG2.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php index 4493515c..18e92791 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImPowerTest.php @@ -14,7 +14,7 @@ class ImPowerTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -36,7 +36,7 @@ class ImPowerTest extends TestCase ); } - public function providerIMPOWER() + public function providerIMPOWER(): array { return require 'tests/data/Calculation/Engineering/IMPOWER.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php index 395153ed..845d436f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImProductTest.php @@ -14,7 +14,7 @@ class ImProductTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -36,7 +36,7 @@ class ImProductTest extends TestCase ); } - public function providerIMPRODUCT() + public function providerIMPRODUCT(): array { return require 'tests/data/Calculation/Engineering/IMPRODUCT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImRealTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImRealTest.php index 08d2feb1..790487c1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImRealTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImRealTest.php @@ -27,7 +27,7 @@ class ImRealTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::COMPLEX_PRECISION); } - public function providerIMREAL() + public function providerIMREAL(): array { return require 'tests/data/Calculation/Engineering/IMREAL.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php index bd9c6df0..b750796d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSecTest.php @@ -14,7 +14,7 @@ class ImSecTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImSecTest extends TestCase ); } - public function providerIMSEC() + public function providerIMSEC(): array { return require 'tests/data/Calculation/Engineering/IMSEC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php index b81e0305..c6477c1c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSechTest.php @@ -14,7 +14,7 @@ class ImSechTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImSechTest extends TestCase ); } - public function providerIMSECH() + public function providerIMSECH(): array { return require 'tests/data/Calculation/Engineering/IMSECH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php index d83980e0..df8cb020 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinTest.php @@ -14,7 +14,7 @@ class ImSinTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImSinTest extends TestCase ); } - public function providerIMSIN() + public function providerIMSIN(): array { return require 'tests/data/Calculation/Engineering/IMSIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php index 107c0949..f8dbafb9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSinhTest.php @@ -14,7 +14,7 @@ class ImSinhTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImSinhTest extends TestCase ); } - public function providerIMSINH() + public function providerIMSINH(): array { return require 'tests/data/Calculation/Engineering/IMSINH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php index c8c83e10..0d536f94 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSqrtTest.php @@ -14,7 +14,7 @@ class ImSqrtTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImSqrtTest extends TestCase ); } - public function providerIMSQRT() + public function providerIMSQRT(): array { return require 'tests/data/Calculation/Engineering/IMSQRT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php index b2b8394e..edb413d5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSubTest.php @@ -14,7 +14,7 @@ class ImSubTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -36,7 +36,7 @@ class ImSubTest extends TestCase ); } - public function providerIMSUB() + public function providerIMSUB(): array { return require 'tests/data/Calculation/Engineering/IMSUB.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php index 872c73c8..0620c684 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImSumTest.php @@ -14,7 +14,7 @@ class ImSumTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -36,7 +36,7 @@ class ImSumTest extends TestCase ); } - public function providerIMSUM() + public function providerIMSUM(): array { return require 'tests/data/Calculation/Engineering/IMSUM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php index 9bf6b66c..f1e4037e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImTanTest.php @@ -14,7 +14,7 @@ class ImTanTest extends TestCase /** * @var ComplexAssert */ - protected $complexAssert; + private $complexAssert; protected function setUp(): void { @@ -37,7 +37,7 @@ class ImTanTest extends TestCase ); } - public function providerIMTAN() + public function providerIMTAN(): array { return require 'tests/data/Calculation/Engineering/IMTAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImaginaryTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImaginaryTest.php index 6ad72287..1c976b05 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImaginaryTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/ImaginaryTest.php @@ -27,7 +27,7 @@ class ImaginaryTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, self::COMPLEX_PRECISION); } - public function providerIMAGINARY() + public function providerIMAGINARY(): array { return require 'tests/data/Calculation/Engineering/IMAGINARY.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php index 6e60a17b..e7f085b1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Oct2BinTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Oct2BinTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerOCT2BIN() + public function providerOCT2BIN(): array { return require 'tests/data/Calculation/Engineering/OCT2BIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php index b0537289..2c354046 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Oct2DecTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Oct2DecTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerOCT2DEC() + public function providerOCT2DEC(): array { return require 'tests/data/Calculation/Engineering/OCT2DEC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php index 05703cc9..3f721a48 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php @@ -9,6 +9,9 @@ use PHPUnit\Framework\TestCase; class Oct2HexTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -40,7 +43,7 @@ class Oct2HexTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerOCT2HEX() + public function providerOCT2HEX(): array { return require 'tests/data/Calculation/Engineering/OCT2HEX.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php index 908e4862..fbc7a61c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintMTest.php @@ -24,7 +24,7 @@ class AccrintMTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerACCRINTM() + public function providerACCRINTM(): array { return require 'tests/data/Calculation/Financial/ACCRINTM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php index 2d31c4cc..74444061 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AccrintTest.php @@ -24,7 +24,7 @@ class AccrintTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerACCRINT() + public function providerACCRINT(): array { return require 'tests/data/Calculation/Financial/ACCRINT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php index 5d0cb8ef..6f69e7fb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorDegRcTest.php @@ -24,7 +24,7 @@ class AmorDegRcTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerAMORDEGRC() + public function providerAMORDEGRC(): array { return require 'tests/data/Calculation/Financial/AMORDEGRC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php index 9f6b1080..959e017f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/AmorLincTest.php @@ -24,7 +24,7 @@ class AmorLincTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerAMORLINC() + public function providerAMORLINC(): array { return require 'tests/data/Calculation/Financial/AMORLINC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php index 670d4dc2..2f71bd57 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDayBsTest.php @@ -24,7 +24,7 @@ class CoupDayBsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCOUPDAYBS() + public function providerCOUPDAYBS(): array { return require 'tests/data/Calculation/Financial/COUPDAYBS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php index da9fc0ea..0b283fcd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysNcTest.php @@ -24,7 +24,7 @@ class CoupDaysNcTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCOUPDAYSNC() + public function providerCOUPDAYSNC(): array { return require 'tests/data/Calculation/Financial/COUPDAYSNC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php index 9e642077..095e6c07 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupDaysTest.php @@ -24,7 +24,7 @@ class CoupDaysTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCOUPDAYS() + public function providerCOUPDAYS(): array { return require 'tests/data/Calculation/Financial/COUPDAYS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php index 75680eaf..297b11b9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNcdTest.php @@ -24,7 +24,7 @@ class CoupNcdTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCOUPNCD() + public function providerCOUPNCD(): array { return require 'tests/data/Calculation/Financial/COUPNCD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php index bff1b097..ccbcec59 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupNumTest.php @@ -24,7 +24,7 @@ class CoupNumTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCOUPNUM() + public function providerCOUPNUM(): array { return require 'tests/data/Calculation/Financial/COUPNUM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php index 465f005e..291a2f24 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CoupPcdTest.php @@ -24,7 +24,7 @@ class CoupPcdTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCOUPPCD() + public function providerCOUPPCD(): array { return require 'tests/data/Calculation/Financial/COUPPCD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php index ff82bcbc..79e9128c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumIpmtTest.php @@ -24,7 +24,7 @@ class CumIpmtTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCUMIPMT() + public function providerCUMIPMT(): array { return require 'tests/data/Calculation/Financial/CUMIPMT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php index d0c3d69d..9d955a6b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/CumPrincTest.php @@ -24,7 +24,7 @@ class CumPrincTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerCUMPRINC() + public function providerCUMPRINC(): array { return require 'tests/data/Calculation/Financial/CUMPRINC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php index 6ea05d15..be2950e5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DbTest.php @@ -24,7 +24,7 @@ class DbTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDB() + public function providerDB(): array { return require 'tests/data/Calculation/Financial/DB.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php index ba7ed0cc..204ed56b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DdbTest.php @@ -24,7 +24,7 @@ class DdbTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDDB() + public function providerDDB(): array { return require 'tests/data/Calculation/Financial/DDB.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php index 5f581028..cf4748c3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DiscTest.php @@ -24,7 +24,7 @@ class DiscTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDISC() + public function providerDISC(): array { return require 'tests/data/Calculation/Financial/DISC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php index ba9116cd..7a4ed042 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarDeTest.php @@ -24,7 +24,7 @@ class DollarDeTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDOLLARDE() + public function providerDOLLARDE(): array { return require 'tests/data/Calculation/Financial/DOLLARDE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php index 21e0d39e..ce74595a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/DollarFrTest.php @@ -24,7 +24,7 @@ class DollarFrTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDOLLARFR() + public function providerDOLLARFR(): array { return require 'tests/data/Calculation/Financial/DOLLARFR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php index fd8bb36f..89c48b6b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/EffectTest.php @@ -26,7 +26,7 @@ class EffectTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerEFFECT() + public function providerEFFECT(): array { return require 'tests/data/Calculation/Financial/EFFECT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php index 3e145325..b82f4db8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvScheduleTest.php @@ -24,7 +24,7 @@ class FvScheduleTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerFVSCHEDULE() + public function providerFVSCHEDULE(): array { return require 'tests/data/Calculation/Financial/FVSCHEDULE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php index 0d24fb4d..cb1a304a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/FvTest.php @@ -24,7 +24,7 @@ class FvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerFV() + public function providerFV(): array { return require 'tests/data/Calculation/Financial/FV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php index d8a5d7d0..ff096247 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/HelpersTest.php @@ -17,10 +17,10 @@ class HelpersTest extends TestCase public function testDaysPerYear($expectedResult, $year, $basis): void { $result = Helpers::daysPerYear($year, $basis); - self::assertSame($expectedResult, $result, 1E-8); + self::assertSame($expectedResult, $result); } - public function providerDaysPerYear() + public function providerDaysPerYear(): array { return require 'tests/data/Calculation/Financial/DaysPerYear.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php index 53d0c81e..443891d7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IPmtTest.php @@ -24,7 +24,7 @@ class IPmtTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIPMT() + public function providerIPMT(): array { return require 'tests/data/Calculation/Financial/IPMT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php index 6533e057..d36b5851 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IntRateTest.php @@ -24,7 +24,7 @@ class IntRateTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerINTRATE() + public function providerINTRATE(): array { return require 'tests/data/Calculation/Financial/INTRATE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php index eb27357b..3c4bdb5a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IrrTest.php @@ -24,7 +24,7 @@ class IrrTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIRR() + public function providerIRR(): array { return require 'tests/data/Calculation/Financial/IRR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php index f41229cd..61e65594 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/IsPmtTest.php @@ -24,7 +24,7 @@ class IsPmtTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerISPMT() + public function providerISPMT(): array { return require 'tests/data/Calculation/Financial/ISPMT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php index 3d8208ac..27abfa42 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/MirrTest.php @@ -24,7 +24,7 @@ class MirrTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerMIRR() + public function providerMIRR(): array { return require 'tests/data/Calculation/Financial/MIRR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php index 01735a12..3c677d90 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NPerTest.php @@ -24,7 +24,7 @@ class NPerTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerNPER() + public function providerNPER(): array { return require 'tests/data/Calculation/Financial/NPER.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php index da8e52f4..50c1c9a8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NominalTest.php @@ -26,7 +26,7 @@ class NominalTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerNOMINAL() + public function providerNOMINAL(): array { return require 'tests/data/Calculation/Financial/NOMINAL.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php index b49fc21e..a5e280c4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/NpvTest.php @@ -24,7 +24,7 @@ class NpvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerNPV() + public function providerNPV(): array { return require 'tests/data/Calculation/Financial/NPV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php index 88e56379..a8d3095a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PDurationTest.php @@ -24,7 +24,7 @@ class PDurationTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerPDURATION() + public function providerPDURATION(): array { return require 'tests/data/Calculation/Financial/PDURATION.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php index 9f7cf755..d996db10 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PmtTest.php @@ -27,7 +27,7 @@ class PmtTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerPMT() + public function providerPMT(): array { return require 'tests/data/Calculation/Financial/PMT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php index bf9c438f..142b0fda 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PpmtTest.php @@ -24,7 +24,7 @@ class PpmtTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerPPMT() + public function providerPPMT(): array { return require 'tests/data/Calculation/Financial/PPMT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php index 503d7a4f..74673bba 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceDiscTest.php @@ -24,7 +24,7 @@ class PriceDiscTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerPRICEDISC() + public function providerPRICEDISC(): array { return require 'tests/data/Calculation/Financial/PRICEDISC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php index 0eb8c104..d3bd4dab 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceMatTest.php @@ -24,7 +24,7 @@ class PriceMatTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerPRICEMAT() + public function providerPRICEMAT(): array { return require 'tests/data/Calculation/Financial/PRICEMAT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php index d3d5bd8d..87981c7e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PriceTest.php @@ -24,7 +24,7 @@ class PriceTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-7); } - public function providerPRICE() + public function providerPRICE(): array { return require 'tests/data/Calculation/Financial/PRICE.php'; } @@ -43,7 +43,7 @@ class PriceTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-7); } - public function providerPRICE3() + public function providerPRICE3(): array { return require 'tests/data/Calculation/Financial/PRICE3.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php index fffb01b8..c1b40231 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/PvTest.php @@ -24,7 +24,7 @@ class PvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerPV() + public function providerPV(): array { return require 'tests/data/Calculation/Financial/PV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php index d8a0cba3..81535ae0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RateTest.php @@ -24,7 +24,7 @@ class RateTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerRATE() + public function providerRATE(): array { return require 'tests/data/Calculation/Financial/RATE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php index 55cb393a..b566d85f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/ReceivedTest.php @@ -24,7 +24,7 @@ class ReceivedTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerRECEIVED() + public function providerRECEIVED(): array { return require 'tests/data/Calculation/Financial/RECEIVED.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php index b0fe81fd..e641b590 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/RriTest.php @@ -24,7 +24,7 @@ class RriTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerRRI() + public function providerRRI(): array { return require 'tests/data/Calculation/Financial/RRI.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php index 81fc0d57..6ea7908d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SlnTest.php @@ -24,7 +24,7 @@ class SlnTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerSLN() + public function providerSLN(): array { return require 'tests/data/Calculation/Financial/SLN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php index c6b4c191..ede82294 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/SydTest.php @@ -24,7 +24,7 @@ class SydTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerSYD() + public function providerSYD(): array { return require 'tests/data/Calculation/Financial/SYD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php index 756a505e..b528b168 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillEqTest.php @@ -24,7 +24,7 @@ class TBillEqTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerTBILLEQ() + public function providerTBILLEQ(): array { return require 'tests/data/Calculation/Financial/TBILLEQ.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php index 458f6a83..1d1b2420 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillPriceTest.php @@ -24,7 +24,7 @@ class TBillPriceTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerTBILLPRICE() + public function providerTBILLPRICE(): array { return require 'tests/data/Calculation/Financial/TBILLPRICE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php index 3c3057fe..51daddc8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/TBillYieldTest.php @@ -24,7 +24,7 @@ class TBillYieldTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerTBILLYIELD() + public function providerTBILLYIELD(): array { return require 'tests/data/Calculation/Financial/TBILLYIELD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php index 02dc54f9..299d7536 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XNpvTest.php @@ -33,7 +33,7 @@ class XNpvTest extends TestCase self::assertEquals($expectedResult, $result, $message); } - public function providerXNPV() + public function providerXNPV(): array { return require 'tests/data/Calculation/Financial/XNPV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php index 042ef298..a6677f3f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/XirrTest.php @@ -33,7 +33,7 @@ class XirrTest extends TestCase self::assertEquals($expectedResult, $result, $message); } - public function providerXIRR() + public function providerXIRR(): array { return require 'tests/data/Calculation/Financial/XIRR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php index a8d5a7e0..1c966d87 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldDiscTest.php @@ -24,7 +24,7 @@ class YieldDiscTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerYIELDDISC() + public function providerYIELDDISC(): array { return require 'tests/data/Calculation/Financial/YIELDDISC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php index 9a1eba28..d689d057 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Financial/YieldMatTest.php @@ -24,7 +24,7 @@ class YieldMatTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerYIELDMAT() + public function providerYIELDMAT(): array { return require 'tests/data/Calculation/Financial/YIELDMAT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php index d315e82a..a1d546b0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/AndTest.php @@ -24,7 +24,7 @@ class AndTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerAND() + public function providerAND(): array { return require 'tests/data/Calculation/Logical/AND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php index cf3a39d4..49e7d1e9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfErrorTest.php @@ -26,7 +26,7 @@ class IfErrorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerIFERROR() + public function providerIFERROR(): array { return require 'tests/data/Calculation/Logical/IFERROR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php index 63302276..ad3f07fc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfNaTest.php @@ -26,7 +26,7 @@ class IfNaTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerIFNA() + public function providerIFNA(): array { return require 'tests/data/Calculation/Logical/IFNA.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php index 571a80e3..b3e21986 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfTest.php @@ -24,7 +24,7 @@ class IfTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerIF() + public function providerIF(): array { return require 'tests/data/Calculation/Logical/IF.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfsTest.php index 15687cd6..6660b9d3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/IfsTest.php @@ -25,7 +25,7 @@ class IfsTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerIFS() + public function providerIFS(): array { return require 'tests/data/Calculation/Logical/IFS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php index 4b7c70be..d236fdcc 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/NotTest.php @@ -24,7 +24,7 @@ class NotTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerNOT() + public function providerNOT(): array { return require 'tests/data/Calculation/Logical/NOT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php index 021cc97b..af67c506 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/OrTest.php @@ -24,7 +24,7 @@ class OrTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerOR() + public function providerOR(): array { return require 'tests/data/Calculation/Logical/OR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php index eacad823..766b1b7c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/SwitchTest.php @@ -24,7 +24,7 @@ class SwitchTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerSwitch() + public function providerSwitch(): array { return require 'tests/data/Calculation/Logical/SWITCH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php index 8ca05f84..27cb359c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Logical/XorTest.php @@ -24,7 +24,7 @@ class XorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerXOR() + public function providerXOR(): array { return require 'tests/data/Calculation/Logical/XOR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php index 17063edc..e6ed234e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/AddressTest.php @@ -24,7 +24,7 @@ class AddressTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerADDRESS() + public function providerADDRESS(): array { return require 'tests/data/Calculation/LookupRef/ADDRESS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php index 01ba6f75..857973ff 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ChooseTest.php @@ -24,7 +24,7 @@ class ChooseTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCHOOSE() + public function providerCHOOSE(): array { return require 'tests/data/Calculation/LookupRef/CHOOSE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php index 61c7d40d..2dfb22d9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnTest.php @@ -26,7 +26,7 @@ class ColumnTest extends TestCase self::assertSame($expectedResult, $result); } - public function providerCOLUMN() + public function providerCOLUMN(): array { return require 'tests/data/Calculation/LookupRef/COLUMN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php index a7908241..e14023cd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/ColumnsTest.php @@ -24,7 +24,7 @@ class ColumnsTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCOLUMNS() + public function providerCOLUMNS(): array { return require 'tests/data/Calculation/LookupRef/COLUMNS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php index 767b6de8..7484c47b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/HLookupTest.php @@ -24,7 +24,7 @@ class HLookupTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerHLOOKUP() + public function providerHLOOKUP(): array { return require 'tests/data/Calculation/LookupRef/HLOOKUP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php index c84a504d..4de661ed 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndexTest.php @@ -25,7 +25,7 @@ class IndexTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerINDEX() + public function providerINDEX(): array { return require 'tests/data/Calculation/LookupRef/INDEX.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php index f1018e7f..b11fce68 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/IndirectTest.php @@ -48,7 +48,7 @@ class IndirectTest extends TestCase self::assertSame($expectedResult, $result); } - public function providerINDIRECT() + public function providerINDIRECT(): array { return require 'tests/data/Calculation/LookupRef/INDIRECT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php index d1b36e4a..73dffd3d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/LookupTest.php @@ -24,7 +24,7 @@ class LookupTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerLOOKUP() + public function providerLOOKUP(): array { return require 'tests/data/Calculation/LookupRef/LOOKUP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php index e020d3ba..ba2dce29 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/MatchTest.php @@ -24,7 +24,7 @@ class MatchTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerMATCH() + public function providerMATCH(): array { return require 'tests/data/Calculation/LookupRef/MATCH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php index 631af08d..31a9703a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/OffsetTest.php @@ -25,7 +25,7 @@ class OffsetTest extends TestCase self::assertSame($expectedResult, $result); } - public function providerOFFSET() + public function providerOFFSET(): array { return require 'tests/data/Calculation/LookupRef/OFFSET.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php index 29a72a28..0e73e829 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowTest.php @@ -26,7 +26,7 @@ class RowTest extends TestCase self::assertSame($expectedResult, $result); } - public function providerROW() + public function providerROW(): array { return require 'tests/data/Calculation/LookupRef/ROW.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php index 62a06626..ec9b33d9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/RowsTest.php @@ -24,7 +24,7 @@ class RowsTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerROWS() + public function providerROWS(): array { return require 'tests/data/Calculation/LookupRef/ROWS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php index 1c75ab09..7654f1bd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/TransposeTest.php @@ -25,7 +25,7 @@ class TransposeTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerTRANSPOSE() + public function providerTRANSPOSE(): array { return require 'tests/data/Calculation/LookupRef/TRANSPOSE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php index badf8f68..35e1e069 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/LookupRef/VLookupTest.php @@ -24,7 +24,7 @@ class VLookupTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerVLOOKUP() + public function providerVLOOKUP(): array { return require 'tests/data/Calculation/LookupRef/VLOOKUP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php index 7e74474a..5dc97e15 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php @@ -24,7 +24,7 @@ class AbsTest extends AllSetupTeardown self::assertSame($expectedResult, $result); } - public function providerAbs() + public function providerAbs(): array { return require 'tests/data/Calculation/MathTrig/ABS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php index f9bdac46..c6372ddb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php @@ -19,7 +19,7 @@ class AcosTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerAcos() + public function providerAcos(): array { return require 'tests/data/Calculation/MathTrig/ACOS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php index 40930582..557da135 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php @@ -19,7 +19,7 @@ class AcoshTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerAcosh() + public function providerAcosh(): array { return require 'tests/data/Calculation/MathTrig/ACOSH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php index de9e2196..d94d4dec 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php @@ -23,7 +23,7 @@ class AcotTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerACOT() + public function providerACOT(): array { return require 'tests/data/Calculation/MathTrig/ACOT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php index f28064f8..a065b496 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php @@ -23,7 +23,7 @@ class AcothTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerACOTH() + public function providerACOTH(): array { return require 'tests/data/Calculation/MathTrig/ACOTH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php index eef757f4..a8630727 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php @@ -6,14 +6,24 @@ use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException; use PhpOffice\PhpSpreadsheet\Calculation\Functions; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PHPUnit\Framework\TestCase; class AllSetupTeardown extends TestCase { - protected $compatibilityMode; + /** + * @var string + */ + private $compatibilityMode; - protected $spreadsheet; + /** + * @var Spreadsheet + */ + private $spreadsheet; + /** + * @var Worksheet + */ protected $sheet; protected function setUp(): void @@ -27,8 +37,6 @@ class AllSetupTeardown extends TestCase { Functions::setCompatibilityMode($this->compatibilityMode); $this->spreadsheet->disconnectWorksheets(); - $this->spreadsheet = null; - $this->sheet = null; } protected static function setOpenOffice(): void diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php index 93ed4f25..c9dbbcce 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php @@ -20,7 +20,7 @@ class ArabicTest extends AllSetupTeardown self::assertSame($expectedResult, $result); } - public function providerARABIC() + public function providerARABIC(): array { return require 'tests/data/Calculation/MathTrig/ARABIC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php index 4797a93f..b3612d01 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php @@ -19,7 +19,7 @@ class AsinTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerAsin() + public function providerAsin(): array { return require 'tests/data/Calculation/MathTrig/ASIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php index 3f63a01c..e8f21142 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php @@ -19,7 +19,7 @@ class AsinhTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerAsinh() + public function providerAsinh(): array { return require 'tests/data/Calculation/MathTrig/ASINH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php index e1d435de..a22d6ad3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php @@ -20,7 +20,7 @@ class Atan2Test extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerATAN2() + public function providerATAN2(): array { return require 'tests/data/Calculation/MathTrig/ATAN2.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php index c92f834a..69f4ed53 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php @@ -19,7 +19,7 @@ class AtanTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerAtan() + public function providerAtan(): array { return require 'tests/data/Calculation/MathTrig/ATAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php index abefd334..20a3e9c0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php @@ -19,7 +19,7 @@ class AtanhTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerAtanh() + public function providerAtanh(): array { return require 'tests/data/Calculation/MathTrig/ATANH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php index 94176c77..8bf0f4b2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php @@ -38,7 +38,7 @@ class BaseTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerBASE() + public function providerBASE(): array { return require 'tests/data/Calculation/MathTrig/BASE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php index cd1dcb33..f4039458 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php @@ -23,7 +23,7 @@ class CeilingMathTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCEILINGMATH() + public function providerCEILINGMATH(): array { return require 'tests/data/Calculation/MathTrig/CEILINGMATH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php index 7c9e289e..c859646b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php @@ -23,7 +23,7 @@ class CeilingPreciseTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFLOORPRECISE() + public function providerFLOORPRECISE(): array { return require 'tests/data/Calculation/MathTrig/CEILINGPRECISE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php index bbbc10ea..d65ac6e9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php @@ -23,7 +23,7 @@ class CeilingTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCEILING() + public function providerCEILING(): array { return require 'tests/data/Calculation/MathTrig/CEILING.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php index 6ab71c7c..45ad8b29 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php @@ -26,7 +26,7 @@ class CombinATest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerCOMBINA() + public function providerCOMBINA(): array { return require 'tests/data/Calculation/MathTrig/COMBINA.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php index 8b2749d8..408b60fe 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php @@ -26,7 +26,7 @@ class CombinTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerCOMBIN() + public function providerCOMBIN(): array { return require 'tests/data/Calculation/MathTrig/COMBIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php index 3a31b454..5bb3427e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php @@ -19,7 +19,7 @@ class CosTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerCos() + public function providerCos(): array { return require 'tests/data/Calculation/MathTrig/COS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php index 83c9315c..c408338f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php @@ -19,7 +19,7 @@ class CoshTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerCosh() + public function providerCosh(): array { return require 'tests/data/Calculation/MathTrig/COSH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php index 5ed9ac78..d096d0da 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php @@ -23,7 +23,7 @@ class CotTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerCOT() + public function providerCOT(): array { return require 'tests/data/Calculation/MathTrig/COT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php index 515ad0a8..11949c43 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php @@ -23,7 +23,7 @@ class CothTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerCOTH() + public function providerCOTH(): array { return require 'tests/data/Calculation/MathTrig/COTH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php index 3b401ef2..ea5a74bf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php @@ -23,7 +23,7 @@ class CscTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerCSC() + public function providerCSC(): array { return require 'tests/data/Calculation/MathTrig/CSC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php index 7cf33099..071f7497 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php @@ -23,7 +23,7 @@ class CschTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerCSCH() + public function providerCSCH(): array { return require 'tests/data/Calculation/MathTrig/CSCH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php index d441a943..10eb3b10 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php @@ -24,7 +24,7 @@ class DegreesTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerDegrees() + public function providerDegrees(): array { return require 'tests/data/Calculation/MathTrig/DEGREES.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php index 56839f7f..12bca051 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php @@ -19,7 +19,7 @@ class EvenTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerEVEN() + public function providerEVEN(): array { return require 'tests/data/Calculation/MathTrig/EVEN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php index 7e4510fa..70e7c650 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php @@ -26,7 +26,7 @@ class ExpTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerEXP() + public function providerEXP(): array { return require 'tests/data/Calculation/MathTrig/EXP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php index 83fe898c..70f06f11 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php @@ -20,7 +20,7 @@ class FactDoubleTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerFACTDOUBLE() + public function providerFACTDOUBLE(): array { return require 'tests/data/Calculation/MathTrig/FACTDOUBLE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php index 855e7605..379b382c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php @@ -26,7 +26,7 @@ class FactTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerFACT() + public function providerFACT(): array { return require 'tests/data/Calculation/MathTrig/FACT.php'; } @@ -54,7 +54,7 @@ class FactTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerFACTGnumeric() + public function providerFACTGnumeric(): array { return require 'tests/data/Calculation/MathTrig/FACTGNUMERIC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php index 35ddd892..ecf4c73a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php @@ -23,7 +23,7 @@ class FloorMathTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFLOORMATH() + public function providerFLOORMATH(): array { return require 'tests/data/Calculation/MathTrig/FLOORMATH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php index bf580134..22dd72ad 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php @@ -23,7 +23,7 @@ class FloorPreciseTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFLOORPRECISE() + public function providerFLOORPRECISE(): array { return require 'tests/data/Calculation/MathTrig/FLOORPRECISE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php index d684e84f..b981b26a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php @@ -23,7 +23,7 @@ class FloorTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFLOOR() + public function providerFLOOR(): array { return require 'tests/data/Calculation/MathTrig/FLOOR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php index 6d87ccc3..aaa641d7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php @@ -29,7 +29,7 @@ class GcdTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerGCD() + public function providerGCD(): array { return require 'tests/data/Calculation/MathTrig/GCD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php index 989b5bd1..29abbf41 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php @@ -23,7 +23,7 @@ class IntTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerINT() + public function providerINT(): array { return require 'tests/data/Calculation/MathTrig/INT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php index 55655d83..5d0ebb58 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php @@ -22,7 +22,7 @@ class LcmTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerLCM() + public function providerLCM(): array { return require 'tests/data/Calculation/MathTrig/LCM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php index e4c46017..3fe35a3c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php @@ -26,7 +26,7 @@ class LnTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerLN() + public function providerLN(): array { return require 'tests/data/Calculation/MathTrig/LN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php index b6afaeda..61cade1d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php @@ -26,7 +26,7 @@ class Log10Test extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerLN() + public function providerLN(): array { return require 'tests/data/Calculation/MathTrig/LOG10.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php index f27ec94a..8c45a840 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php @@ -32,7 +32,7 @@ class LogTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerLOG() + public function providerLOG(): array { return require 'tests/data/Calculation/MathTrig/LOG.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php index 1912fe07..30a40726 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php @@ -17,7 +17,7 @@ class MInverseTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerMINVERSE() + public function providerMINVERSE(): array { return require 'tests/data/Calculation/MathTrig/MINVERSE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php index 5e0d45f5..49474c14 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php @@ -17,7 +17,7 @@ class MMultTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerMMULT() + public function providerMMULT(): array { return require 'tests/data/Calculation/MathTrig/MMULT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php index 404193e9..e7aa0f41 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php @@ -23,7 +23,7 @@ class MRoundTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMROUND() + public function providerMROUND(): array { return require 'tests/data/Calculation/MathTrig/MROUND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php index b86a90c0..b2cb4bb2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php @@ -26,7 +26,7 @@ class MdeTermTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMDETERM() + public function providerMDETERM(): array { return require 'tests/data/Calculation/MathTrig/MDETERM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php index 3035e39c..ff35657f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php @@ -32,7 +32,7 @@ class ModTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMOD() + public function providerMOD(): array { return require 'tests/data/Calculation/MathTrig/MOD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php index 1c22cc40..3fea7651 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php @@ -27,7 +27,7 @@ class MultinomialTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMULTINOMIAL() + public function providerMULTINOMIAL(): array { return require 'tests/data/Calculation/MathTrig/MULTINOMIAL.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php index 21740ef3..37042743 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php @@ -19,7 +19,7 @@ class OddTest extends AllSetupTeardown self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue()); } - public function providerODD() + public function providerODD(): array { return require 'tests/data/Calculation/MathTrig/ODD.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php index f68941b8..4d6ba7e2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php @@ -32,7 +32,7 @@ class PowerTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPOWER() + public function providerPOWER(): array { return require 'tests/data/Calculation/MathTrig/POWER.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php index c38eb130..4e63ae91 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php @@ -22,7 +22,7 @@ class ProductTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPRODUCT() + public function providerPRODUCT(): array { return require 'tests/data/Calculation/MathTrig/PRODUCT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php index 3df2ed99..c8cd13b7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php @@ -32,7 +32,7 @@ class QuotientTest extends AllSetupTeardown self::assertSame($expectedResult, $result); } - public function providerQUOTIENT() + public function providerQUOTIENT(): array { return require 'tests/data/Calculation/MathTrig/QUOTIENT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php index 00af620e..03cceaac 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php @@ -24,7 +24,7 @@ class RadiansTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerRADIANS() + public function providerRADIANS(): array { return require 'tests/data/Calculation/MathTrig/RADIANS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php index 0efe8ba6..2e1ba676 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php @@ -39,7 +39,7 @@ class RandBetweenTest extends AllSetupTeardown } } - public function providerRANDBETWEEN() + public function providerRANDBETWEEN(): array { return require 'tests/data/Calculation/MathTrig/RANDBETWEEN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php index 0d71ece0..417656c0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php @@ -20,7 +20,7 @@ class RomanTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerROMAN() + public function providerROMAN(): array { return require 'tests/data/Calculation/MathTrig/ROMAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php index e450c29e..97058102 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php @@ -23,7 +23,7 @@ class RoundDownTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerRoundDown() + public function providerRoundDown(): array { return require 'tests/data/Calculation/MathTrig/ROUNDDOWN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php index ee52b93d..960f4740 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php @@ -23,7 +23,7 @@ class RoundTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerRound() + public function providerRound(): array { return require 'tests/data/Calculation/MathTrig/ROUND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php index 6aa6c796..f9ba44e0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php @@ -23,7 +23,7 @@ class RoundUpTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerRoundUp() + public function providerRoundUp(): array { return require 'tests/data/Calculation/MathTrig/ROUNDUP.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php index 6a008102..ad52cee2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php @@ -23,7 +23,7 @@ class SecTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerSEC() + public function providerSEC(): array { return require 'tests/data/Calculation/MathTrig/SEC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php index a93f37c5..7dabf291 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php @@ -23,7 +23,7 @@ class SechTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-9); } - public function providerSECH() + public function providerSECH(): array { return require 'tests/data/Calculation/MathTrig/SECH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php index 86a40d07..9070f60b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php @@ -39,7 +39,7 @@ class SeriesSumTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSERIESSUM() + public function providerSERIESSUM(): array { return require 'tests/data/Calculation/MathTrig/SERIESSUM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php index 0ec90e78..fd1a3e6c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php @@ -22,7 +22,7 @@ class SignTest extends AllSetupTeardown self::assertEquals($expectedResult, $result); } - public function providerSIGN() + public function providerSIGN(): array { return require 'tests/data/Calculation/MathTrig/SIGN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php index c460605f..c2d0afe5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php @@ -19,7 +19,7 @@ class SinTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerSin() + public function providerSin(): array { return require 'tests/data/Calculation/MathTrig/SIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php index 30c40615..bb680f08 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php @@ -19,7 +19,7 @@ class SinhTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerCosh() + public function providerCosh(): array { return require 'tests/data/Calculation/MathTrig/SINH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php index fe130d8c..1a879056 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php @@ -26,7 +26,7 @@ class SqrtPiTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSQRTPI() + public function providerSQRTPI(): array { return require 'tests/data/Calculation/MathTrig/SQRTPI.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php index 9e82fe70..8ce557bd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php @@ -24,7 +24,7 @@ class SqrtTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerSqrt() + public function providerSqrt(): array { return require 'tests/data/Calculation/MathTrig/SQRT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php index 7d44c551..fde1d16e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php @@ -22,7 +22,7 @@ class SubTotalTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUBTOTAL() + public function providerSUBTOTAL(): array { return require 'tests/data/Calculation/MathTrig/SUBTOTAL.php'; } @@ -98,7 +98,7 @@ class SubTotalTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUBTOTALHIDDEN() + public function providerSUBTOTALHIDDEN(): array { return require 'tests/data/Calculation/MathTrig/SUBTOTALHIDDEN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php index 7bcd274e..ad560423 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php @@ -35,7 +35,7 @@ class SumIfTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMIF() + public function providerSUMIF(): array { return require 'tests/data/Calculation/MathTrig/SUMIF.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php index a4a99888..1ae6e231 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfsTest.php @@ -17,7 +17,7 @@ class SumIfsTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMIFS() + public function providerSUMIFS(): array { return require 'tests/data/Calculation/MathTrig/SUMIFS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php index 6e7f49e8..b2cdb379 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php @@ -34,7 +34,7 @@ class SumProductTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMPRODUCT() + public function providerSUMPRODUCT(): array { return require 'tests/data/Calculation/MathTrig/SUMPRODUCT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php index e811dd75..162c578a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php @@ -27,7 +27,7 @@ class SumSqTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMSQ() + public function providerSUMSQ(): array { return require 'tests/data/Calculation/MathTrig/SUMSQ.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php index 5bd03318..a9ea7f29 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php @@ -22,7 +22,7 @@ class SumTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUM() + public function providerSUM(): array { return require 'tests/data/Calculation/MathTrig/SUM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php index a6813bb2..427e5c85 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php @@ -34,7 +34,7 @@ class SumX2MY2Test extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMX2MY2() + public function providerSUMX2MY2(): array { return require 'tests/data/Calculation/MathTrig/SUMX2MY2.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php index 2db78440..100b8566 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php @@ -34,7 +34,7 @@ class SumX2PY2Test extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMX2PY2() + public function providerSUMX2PY2(): array { return require 'tests/data/Calculation/MathTrig/SUMX2PY2.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php index eaa1ec7a..43acd4a0 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php @@ -34,7 +34,7 @@ class SumXMY2Test extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSUMXMY2() + public function providerSUMXMY2(): array { return require 'tests/data/Calculation/MathTrig/SUMXMY2.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php index 4db9dbb9..80dd7eff 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php @@ -19,7 +19,7 @@ class TanTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerTan() + public function providerTan(): array { return require 'tests/data/Calculation/MathTrig/TAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php index 68f87cd2..9a55e9b4 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php @@ -19,7 +19,7 @@ class TanhTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-6); } - public function providerTanh() + public function providerTanh(): array { return require 'tests/data/Calculation/MathTrig/TANH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php index e4127e57..7d7a4b55 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php @@ -23,7 +23,7 @@ class TruncTest extends AllSetupTeardown self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerTRUNC() + public function providerTRUNC(): array { return require 'tests/data/Calculation/MathTrig/TRUNC.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php index 571c06c3..ea3df6bb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php @@ -24,7 +24,7 @@ class AveDevTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerAVEDEV() + public function providerAVEDEV(): array { return require 'tests/data/Calculation/Statistical/AVEDEV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php index 1af96dfc..fec65c28 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageATest.php @@ -24,7 +24,7 @@ class AverageATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerAVERAGEA() + public function providerAVERAGEA(): array { return require 'tests/data/Calculation/Statistical/AVERAGEA.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php index 69dcfb87..c9648d43 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfTest.php @@ -24,7 +24,7 @@ class AverageIfTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerAVERAGEIF() + public function providerAVERAGEIF(): array { return require 'tests/data/Calculation/Statistical/AVERAGEIF.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php index 84c53431..de593764 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageIfsTest.php @@ -24,7 +24,7 @@ class AverageIfsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerAVERAGEIFS() + public function providerAVERAGEIFS(): array { return require 'tests/data/Calculation/Statistical/AVERAGEIFS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php index c67452ab..d5e617a9 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AverageTest.php @@ -24,7 +24,7 @@ class AverageTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerAVERAGE() + public function providerAVERAGE(): array { return require 'tests/data/Calculation/Statistical/AVERAGE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php index a85781e5..03d03372 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaDistTest.php @@ -24,7 +24,7 @@ class BetaDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerBETADIST() + public function providerBETADIST(): array { return require 'tests/data/Calculation/Statistical/BETADIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php index 24ddd3fc..d82008ab 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BetaInvTest.php @@ -24,7 +24,7 @@ class BetaInvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerBETAINV() + public function providerBETAINV(): array { return require 'tests/data/Calculation/Statistical/BETAINV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php index 8db391e1..6d53aed3 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistRangeTest.php @@ -24,7 +24,7 @@ class BinomDistRangeTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerBINOMDISTRANGE() + public function providerBINOMDISTRANGE(): array { return require 'tests/data/Calculation/Statistical/BINOMDISTRANGE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php index 8b3e6856..5c4b8d16 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomDistTest.php @@ -24,7 +24,7 @@ class BinomDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerBINOMDIST() + public function providerBINOMDIST(): array { return require 'tests/data/Calculation/Statistical/BINOMDIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php index 91381dd7..88a37ede 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/BinomInvTest.php @@ -24,7 +24,7 @@ class BinomInvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerBINOMINV() + public function providerBINOMINV(): array { return require 'tests/data/Calculation/Statistical/BINOMINV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php index 3c7a8d4e..7955fcec 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistLeftTailTest.php @@ -24,7 +24,7 @@ class ChiDistLeftTailTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCHIDIST() + public function providerCHIDIST(): array { return require 'tests/data/Calculation/Statistical/CHIDISTLeftTail.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php index 26bf5ab7..edf275ec 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiDistRightTailTest.php @@ -24,7 +24,7 @@ class ChiDistRightTailTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCHIDIST() + public function providerCHIDIST(): array { return require 'tests/data/Calculation/Statistical/CHIDISTRightTail.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php index 962e20ad..0911449d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvLeftTailTest.php @@ -30,7 +30,7 @@ class ChiInvLeftTailTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCHIINV() + public function providerCHIINV(): array { return require 'tests/data/Calculation/Statistical/CHIINVLeftTail.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php index 75949f39..29ef161f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiInvRightTailTest.php @@ -30,7 +30,7 @@ class ChiInvRightTailTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCHIINV() + public function providerCHIINV(): array { return require 'tests/data/Calculation/Statistical/CHIINVRightTail.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php index 5f9f361f..ed608d58 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ChiTestTest.php @@ -20,7 +20,7 @@ class ChiTestTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCHITEST() + public function providerCHITEST(): array { return require 'tests/data/Calculation/Statistical/CHITEST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php index d4bc586f..3e43234a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ConfidenceTest.php @@ -24,7 +24,7 @@ class ConfidenceTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCONFIDENCE() + public function providerCONFIDENCE(): array { return require 'tests/data/Calculation/Statistical/CONFIDENCE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CorrelTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CorrelTest.php index 960a4cfd..adadf422 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CorrelTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CorrelTest.php @@ -26,7 +26,7 @@ class CorrelTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCORREL() + public function providerCORREL(): array { return require 'tests/data/Calculation/Statistical/CORREL.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php index 2df0ebd1..0e530158 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountATest.php @@ -24,7 +24,7 @@ class CountATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCOUNTA() + public function providerCOUNTA(): array { return require 'tests/data/Calculation/Statistical/COUNTA.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php index b0c6698b..24667a6b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountBlankTest.php @@ -24,7 +24,7 @@ class CountBlankTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCOUNTBLANK() + public function providerCOUNTBLANK(): array { return require 'tests/data/Calculation/Statistical/COUNTBLANK.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php index fed32e5c..c42d7eef 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfTest.php @@ -24,7 +24,7 @@ class CountIfTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCOUNTIF() + public function providerCOUNTIF(): array { return require 'tests/data/Calculation/Statistical/COUNTIF.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php index 1eeb4f67..a68d7240 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountIfsTest.php @@ -24,7 +24,7 @@ class CountIfsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCOUNTIFS() + public function providerCOUNTIFS(): array { return require 'tests/data/Calculation/Statistical/COUNTIFS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php index 65b698e3..07f4f918 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CountTest.php @@ -8,6 +8,9 @@ use PHPUnit\Framework\TestCase; class CountTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; protected function setUp(): void @@ -32,7 +35,7 @@ class CountTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerBasicCOUNT() + public function providerBasicCOUNT(): array { return require 'tests/data/Calculation/Statistical/BasicCOUNT.php'; } @@ -48,7 +51,7 @@ class CountTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerExcelCOUNT() + public function providerExcelCOUNT(): array { return require 'tests/data/Calculation/Statistical/ExcelCOUNT.php'; } @@ -66,7 +69,7 @@ class CountTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOpenOfficeCOUNT() + public function providerOpenOfficeCOUNT(): array { return require 'tests/data/Calculation/Statistical/OpenOfficeCOUNT.php'; } @@ -84,7 +87,7 @@ class CountTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerGnumericCOUNT() + public function providerGnumericCOUNT(): array { return require 'tests/data/Calculation/Statistical/GnumericCOUNT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php index 5b73d1d9..e85c6f92 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/CovarTest.php @@ -24,7 +24,7 @@ class CovarTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerCOVAR() + public function providerCOVAR(): array { return require 'tests/data/Calculation/Statistical/COVAR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php index 0296ab7b..200ab14c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ExponDistTest.php @@ -24,7 +24,7 @@ class ExponDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerEXPONDIST() + public function providerEXPONDIST(): array { return require 'tests/data/Calculation/Statistical/EXPONDIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php index 2c3e592c..05fac316 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherInvTest.php @@ -25,7 +25,7 @@ class FisherInvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFISHERINV() + public function providerFISHERINV(): array { return require 'tests/data/Calculation/Statistical/FISHERINV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php index 7705517a..c3dc631d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/FisherTest.php @@ -25,7 +25,7 @@ class FisherTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFISHER() + public function providerFISHER(): array { return require 'tests/data/Calculation/Statistical/FISHER.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php index 6ecbb9c8..80c46b43 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ForecastTest.php @@ -24,7 +24,7 @@ class ForecastTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerFORECAST() + public function providerFORECAST(): array { return require 'tests/data/Calculation/Statistical/FORECAST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php index 6765d340..2d90afc6 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaDistTest.php @@ -24,7 +24,7 @@ class GammaDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerGAMMADIST() + public function providerGAMMADIST(): array { return require 'tests/data/Calculation/Statistical/GAMMADIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php index 3e9e41cb..f845d07c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaInvTest.php @@ -24,7 +24,7 @@ class GammaInvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerGAMMAINV() + public function providerGAMMAINV(): array { return require 'tests/data/Calculation/Statistical/GAMMAINV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php index 31407feb..73dfe23a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GammaLnTest.php @@ -25,7 +25,7 @@ class GammaLnTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerGAMMALN() + public function providerGAMMALN(): array { return require 'tests/data/Calculation/Statistical/GAMMALN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php index 99f125d1..859212f5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GeoMeanTest.php @@ -24,7 +24,7 @@ class GeoMeanTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerGEOMEAN() + public function providerGEOMEAN(): array { return require 'tests/data/Calculation/Statistical/GEOMEAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php index 6e1cf7bf..a5ed8223 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/GrowthTest.php @@ -26,7 +26,7 @@ class GrowthTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result[0], 1E-12); } - public function providerGROWTH() + public function providerGROWTH(): array { return require 'tests/data/Calculation/Statistical/GROWTH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php index 5ddf58a8..2dbc0cba 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HarMeanTest.php @@ -24,7 +24,7 @@ class HarMeanTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerHARMEAN() + public function providerHARMEAN(): array { return require 'tests/data/Calculation/Statistical/HARMEAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php index d05b60b5..1fa02440 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/HypGeomDistTest.php @@ -18,7 +18,7 @@ class HypGeomDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerHYPGEOMDIST() + public function providerHYPGEOMDIST(): array { return require 'tests/data/Calculation/Statistical/HYPGEOMDIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php index 51245861..9ccea5cb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/InterceptTest.php @@ -24,7 +24,7 @@ class InterceptTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerINTERCEPT() + public function providerINTERCEPT(): array { return require 'tests/data/Calculation/Statistical/INTERCEPT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php index b62aa026..d793736a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/KurtTest.php @@ -12,13 +12,13 @@ class KurtTest extends TestCase * * @param mixed $expectedResult */ - public function testKURT($expectedResult, ...$values): void + public function testKURT($expectedResult, ...$args): void { - $result = Statistical::KURT(...$values); + $result = Statistical::KURT(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerKURT() + public function providerKURT(): array { return require 'tests/data/Calculation/Statistical/KURT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php index 194248d0..18694210 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LargeTest.php @@ -20,7 +20,7 @@ class LargeTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerLARGE() + public function providerLARGE(): array { return require 'tests/data/Calculation/Statistical/LARGE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php index 083ac899..539d915f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LinEstTest.php @@ -10,15 +10,15 @@ class LinEstTest extends TestCase /** * @dataProvider providerLINEST * - * @param mixed $expectedResult * @param mixed $xValues * @param mixed $yValues * @param mixed $const * @param mixed $stats */ - public function testLINEST($expectedResult, $yValues, $xValues, $const, $stats): void + public function testLINEST(array $expectedResult, $yValues, $xValues, $const, $stats): void { $result = Statistical::LINEST($yValues, $xValues, $const, $stats); + self::assertIsArray($result); $elements = count($expectedResult); for ($element = 0; $element < $elements; ++$element) { @@ -26,7 +26,7 @@ class LinEstTest extends TestCase } } - public function providerLINEST() + public function providerLINEST(): array { return require 'tests/data/Calculation/Statistical/LINEST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php index 2b2d1ecf..1537de69 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/LogEstTest.php @@ -10,23 +10,23 @@ class LogEstTest extends TestCase /** * @dataProvider providerLOGEST * - * @param mixed $expectedResult * @param mixed $xValues * @param mixed $yValues * @param mixed $const * @param mixed $stats */ - public function testLOGEST($expectedResult, $yValues, $xValues, $const, $stats): void + public function testLOGEST(array $expectedResult, $yValues, $xValues, $const, $stats): void { $result = Statistical::LOGEST($yValues, $xValues, $const, $stats); - //var_dump($result); + self::assertIsArray($result); + $elements = count($expectedResult); for ($element = 0; $element < $elements; ++$element) { self::assertEqualsWithDelta($expectedResult[$element], $result[$element], 1E-12); } } - public function providerLOGEST() + public function providerLOGEST(): array { return require 'tests/data/Calculation/Statistical/LOGEST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php index a031203a..d4c00a4b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MaxIfsTest.php @@ -24,7 +24,7 @@ class MaxIfsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMAXIFS() + public function providerMAXIFS(): array { return require 'tests/data/Calculation/Statistical/MAXIFS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php index c29d65e5..68e46e18 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MedianTest.php @@ -24,7 +24,7 @@ class MedianTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMEDIAN() + public function providerMEDIAN(): array { return require 'tests/data/Calculation/Statistical/MEDIAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php index f1740110..201e9e74 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/MinIfsTest.php @@ -24,7 +24,7 @@ class MinIfsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerMINIFS() + public function providerMINIFS(): array { return require 'tests/data/Calculation/Statistical/MINIFS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php index 9c082da7..d7c7bc53 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NegBinomDistTest.php @@ -24,7 +24,7 @@ class NegBinomDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerNEGBINOMDIST() + public function providerNEGBINOMDIST(): array { return require 'tests/data/Calculation/Statistical/NEGBINOMDIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php index b456f0ae..62a7cf16 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/NormInvTest.php @@ -18,7 +18,7 @@ class NormInvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerNORMINV() + public function providerNORMINV(): array { return require 'tests/data/Calculation/Statistical/NORMINV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php index 71eff7ac..4022ae40 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentRankTest.php @@ -27,7 +27,7 @@ class PercentRankTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPERCENTRANK() + public function providerPERCENTRANK(): array { return require 'tests/data/Calculation/Statistical/PERCENTRANK.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php index ad8c35ed..e4dadb74 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PercentileTest.php @@ -24,7 +24,7 @@ class PercentileTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPERCENTILE() + public function providerPERCENTILE(): array { return require 'tests/data/Calculation/Statistical/PERCENTILE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php index 98e39978..10a4f709 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutTest.php @@ -24,7 +24,7 @@ class PermutTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPERMUT() + public function providerPERMUT(): array { return require 'tests/data/Calculation/Statistical/PERMUT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php index 8a256ae8..ac052e42 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PermutationATest.php @@ -24,7 +24,7 @@ class PermutationATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPERMUT() + public function providerPERMUT(): array { return require 'tests/data/Calculation/Statistical/PERMUTATIONA.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php index e511d0fe..adea549c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/PoissonTest.php @@ -24,7 +24,7 @@ class PoissonTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerPOISSON() + public function providerPOISSON(): array { return require 'tests/data/Calculation/Statistical/POISSON.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php index 706b632e..33b3c599 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/QuartileTest.php @@ -24,7 +24,7 @@ class QuartileTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerQUARTILE() + public function providerQUARTILE(): array { return require 'tests/data/Calculation/Statistical/QUARTILE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php index 9e2ed513..bbbac36f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RankTest.php @@ -27,7 +27,7 @@ class RankTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerRANK() + public function providerRANK(): array { return require 'tests/data/Calculation/Statistical/RANK.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php index 423cc3ae..a85bba06 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/RsqTest.php @@ -24,7 +24,7 @@ class RsqTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerRSQ() + public function providerRSQ(): array { return require 'tests/data/Calculation/Statistical/RSQ.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php index 79714d3f..4415ec4a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SkewTest.php @@ -24,7 +24,7 @@ class SkewTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSKEW() + public function providerSKEW(): array { return require 'tests/data/Calculation/Statistical/SKEW.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php index 467bff1e..9bab264c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SlopeTest.php @@ -24,7 +24,7 @@ class SlopeTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSLOPE() + public function providerSLOPE(): array { return require 'tests/data/Calculation/Statistical/SLOPE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php index a40e5eb3..52c82f6b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SmallTest.php @@ -20,7 +20,7 @@ class SmallTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSMALL() + public function providerSMALL(): array { return require 'tests/data/Calculation/Statistical/SMALL.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php index 79e4482a..1de33a77 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevATest.php @@ -25,7 +25,7 @@ class StDevATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSTDEVA() + public function providerSTDEVA(): array { return require 'tests/data/Calculation/Statistical/STDEVA.php'; } @@ -44,7 +44,7 @@ class StDevATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsSTDEVA() + public function providerOdsSTDEVA(): array { return require 'tests/data/Calculation/Statistical/STDEVA_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php index b004e5b0..f19f072e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPATest.php @@ -25,7 +25,7 @@ class StDevPATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSTDEVPA() + public function providerSTDEVPA(): array { return require 'tests/data/Calculation/Statistical/STDEVPA.php'; } @@ -44,7 +44,7 @@ class StDevPATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsSTDEVPA() + public function providerOdsSTDEVPA(): array { return require 'tests/data/Calculation/Statistical/STDEVPA_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php index 7e45ec51..39de961d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevPTest.php @@ -25,7 +25,7 @@ class StDevPTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSTDEVP() + public function providerSTDEVP(): array { return require 'tests/data/Calculation/Statistical/STDEVP.php'; } @@ -44,7 +44,7 @@ class StDevPTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsSTDEVP() + public function providerOdsSTDEVP(): array { return require 'tests/data/Calculation/Statistical/STDEVP_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php index bc59869d..e9904109 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/StDevTest.php @@ -25,7 +25,7 @@ class StDevTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSTDEV() + public function providerSTDEV(): array { return require 'tests/data/Calculation/Statistical/STDEV.php'; } @@ -44,7 +44,7 @@ class StDevTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsSTDEV() + public function providerOdsSTDEV(): array { return require 'tests/data/Calculation/Statistical/STDEV_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php index ab109345..cefc79c5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/SteyxTest.php @@ -24,7 +24,7 @@ class SteyxTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerSTEYX() + public function providerSTEYX(): array { return require 'tests/data/Calculation/Statistical/STEYX.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php index a6a2c97e..e1fb2546 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TDistTest.php @@ -21,7 +21,7 @@ class TDistTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerTDIST() + public function providerTDIST(): array { return require 'tests/data/Calculation/Statistical/TDIST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php index 62605fe9..08ac3ceb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TinvTest.php @@ -20,7 +20,7 @@ class TinvTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerTINV() + public function providerTINV(): array { return require 'tests/data/Calculation/Statistical/TINV.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php index b4f756b5..c367cb10 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrendTest.php @@ -26,7 +26,7 @@ class TrendTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result[0], 1E-12); } - public function providerGROWTH() + public function providerGROWTH(): array { return require 'tests/data/Calculation/Statistical/TREND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php index cfcb1609..54d7576a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/TrimMeanTest.php @@ -25,7 +25,7 @@ class TrimMeanTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerTRIMMEAN() + public function providerTRIMMEAN(): array { return require 'tests/data/Calculation/Statistical/TRIMMEAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php index 8d664af4..a0bf8182 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarATest.php @@ -25,7 +25,7 @@ class VarATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerVARA() + public function providerVARA(): array { return require 'tests/data/Calculation/Statistical/VARA.php'; } @@ -44,7 +44,7 @@ class VarATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsVARA() + public function providerOdsVARA(): array { return require 'tests/data/Calculation/Statistical/VARA_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php index 8240b5cf..88304d8e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPATest.php @@ -25,7 +25,7 @@ class VarPATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerVARPA() + public function providerVARPA(): array { return require 'tests/data/Calculation/Statistical/VARPA.php'; } @@ -44,7 +44,7 @@ class VarPATest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsVARPA() + public function providerOdsVARPA(): array { return require 'tests/data/Calculation/Statistical/VARPA_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php index bbc5239c..1a0475eb 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarPTest.php @@ -25,7 +25,7 @@ class VarPTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerVARP() + public function providerVARP(): array { return require 'tests/data/Calculation/Statistical/VARP.php'; } @@ -44,7 +44,7 @@ class VarPTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsVARP() + public function providerOdsVARP(): array { return require 'tests/data/Calculation/Statistical/VARP_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php index 15aa98a0..5fc163b5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/VarTest.php @@ -25,7 +25,7 @@ class VarTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerVAR() + public function providerVAR(): array { return require 'tests/data/Calculation/Statistical/VAR.php'; } @@ -44,7 +44,7 @@ class VarTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerOdsVAR() + public function providerOdsVAR(): array { return require 'tests/data/Calculation/Statistical/VAR_ODS.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php index 6707121e..3e97bff8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/WeibullTest.php @@ -22,7 +22,7 @@ class WeibullTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerWEIBULL() + public function providerWEIBULL(): array { return require 'tests/data/Calculation/Statistical/WEIBULL.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php index 9b90079e..4dc3af9b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ZTestTest.php @@ -21,7 +21,7 @@ class ZTestTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-12); } - public function providerZTEST() + public function providerZTEST(): array { return require 'tests/data/Calculation/Statistical/ZTEST.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php index 324f5054..e8934ce5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CharTest.php @@ -19,7 +19,7 @@ class CharTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCHAR() + public function providerCHAR(): array { return require 'tests/data/Calculation/TextData/CHAR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php index ddc27a5d..e3ad5544 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CleanTest.php @@ -19,7 +19,7 @@ class CleanTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCLEAN() + public function providerCLEAN(): array { return require 'tests/data/Calculation/TextData/CLEAN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php index 7bf5a00f..6f0f6b06 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/CodeTest.php @@ -19,7 +19,7 @@ class CodeTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCODE() + public function providerCODE(): array { return require 'tests/data/Calculation/TextData/CODE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php index 068e7d8f..88ad6bfd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ConcatenateTest.php @@ -18,7 +18,7 @@ class ConcatenateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCONCATENATE() + public function providerCONCATENATE(): array { return require 'tests/data/Calculation/TextData/CONCATENATE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php index 1d482589..4abf3909 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/DollarTest.php @@ -18,7 +18,7 @@ class DollarTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDOLLAR() + public function providerDOLLAR(): array { return require 'tests/data/Calculation/TextData/DOLLAR.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php index 92d3935c..e856832f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ExactTest.php @@ -19,10 +19,7 @@ class ExactTest extends TestCase self::assertSame($expectedResult, $result); } - /** - * @return array - */ - public function providerEXACT() + public function providerEXACT(): array { return require 'tests/data/Calculation/TextData/EXACT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php index d4b1b77d..3631c6a7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FindTest.php @@ -18,7 +18,7 @@ class FindTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerFIND() + public function providerFIND(): array { return require 'tests/data/Calculation/TextData/FIND.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php index 0cbaf80c..ab3cfb7a 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/FixedTest.php @@ -18,7 +18,7 @@ class FixedTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerFIXED() + public function providerFIXED(): array { return require 'tests/data/Calculation/TextData/FIXED.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php index 450643f7..c2508dfd 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LeftTest.php @@ -24,7 +24,7 @@ class LeftTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerLEFT() + public function providerLEFT(): array { return require 'tests/data/Calculation/TextData/LEFT.php'; } @@ -51,7 +51,7 @@ class LeftTest extends TestCase Settings::setLocale('en_US'); } - public function providerLocaleLEFT() + public function providerLocaleLEFT(): array { return [ ['VR', 'fr_FR', true, 2], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php index c6ffc43d..7ab36b67 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LenTest.php @@ -19,7 +19,7 @@ class LenTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerLEN() + public function providerLEN(): array { return require 'tests/data/Calculation/TextData/LEN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php index f90ab378..1d11f1e5 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/LowerTest.php @@ -25,7 +25,7 @@ class LowerTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerLOWER() + public function providerLOWER(): array { return require 'tests/data/Calculation/TextData/LOWER.php'; } @@ -51,7 +51,7 @@ class LowerTest extends TestCase Settings::setLocale('en_US'); } - public function providerLocaleLOWER() + public function providerLocaleLOWER(): array { return [ ['vrai', 'fr_FR', true], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php index c9859969..267d6894 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/MidTest.php @@ -24,7 +24,7 @@ class MidTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerMID() + public function providerMID(): array { return require 'tests/data/Calculation/TextData/MID.php'; } @@ -52,7 +52,7 @@ class MidTest extends TestCase Settings::setLocale('en_US'); } - public function providerLocaleMID() + public function providerLocaleMID(): array { return [ ['RA', 'fr_FR', true, 2, 2], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php index c186bb0b..f54bfc3d 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/NumberValueTest.php @@ -18,7 +18,7 @@ class NumberValueTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerNUMBERVALUE() + public function providerNUMBERVALUE(): array { return require 'tests/data/Calculation/TextData/NUMBERVALUE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php index 58096c5e..8366b070 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ProperTest.php @@ -25,7 +25,7 @@ class ProperTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerPROPER() + public function providerPROPER(): array { return require 'tests/data/Calculation/TextData/PROPER.php'; } @@ -51,7 +51,7 @@ class ProperTest extends TestCase Settings::setLocale('en_US'); } - public function providerLocaleLOWER() + public function providerLocaleLOWER(): array { return [ ['Vrai', 'fr_FR', true], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php index ff9236e6..781e454c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReplaceTest.php @@ -18,7 +18,7 @@ class ReplaceTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerREPLACE() + public function providerREPLACE(): array { return require 'tests/data/Calculation/TextData/REPLACE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php index 8c637f9a..a0c089cf 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php @@ -51,7 +51,7 @@ class ReptTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerREPT() + public function providerREPT(): array { return require 'tests/data/Calculation/TextData/REPT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php index 26ccc549..a2ab3a4c 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/RightTest.php @@ -24,7 +24,7 @@ class RightTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerRIGHT() + public function providerRIGHT(): array { return require 'tests/data/Calculation/TextData/RIGHT.php'; } @@ -51,7 +51,7 @@ class RightTest extends TestCase Settings::setLocale('en_US'); } - public function providerLocaleRIGHT() + public function providerLocaleRIGHT(): array { return [ ['RAI', 'fr_FR', true, 3], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php index 7bb92e83..14f5735b 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SearchTest.php @@ -18,7 +18,7 @@ class SearchTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerSEARCH() + public function providerSEARCH(): array { return require 'tests/data/Calculation/TextData/SEARCH.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php index 2a9d1012..792e1a15 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/SubstituteTest.php @@ -18,7 +18,7 @@ class SubstituteTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerSUBSTITUTE() + public function providerSUBSTITUTE(): array { return require 'tests/data/Calculation/TextData/SUBSTITUTE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php index e2f5cd01..9ca47f91 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TTest.php @@ -19,7 +19,7 @@ class TTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerT() + public function providerT(): array { return require 'tests/data/Calculation/TextData/T.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php index e8fb404d..78e72f96 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextJoinTest.php @@ -18,7 +18,7 @@ class TextJoinTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerTEXTJOIN() + public function providerTEXTJOIN(): array { return require 'tests/data/Calculation/TextData/TEXTJOIN.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php index 8d7b238b..91418065 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TextTest.php @@ -18,7 +18,7 @@ class TextTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerTEXT() + public function providerTEXT(): array { return require 'tests/data/Calculation/TextData/TEXT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php index 6b2dbc7a..302dce4f 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/TrimTest.php @@ -19,7 +19,7 @@ class TrimTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerTRIM() + public function providerTRIM(): array { return require 'tests/data/Calculation/TextData/TRIM.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php index 352aa5b7..45f7aea8 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/UpperTest.php @@ -25,7 +25,7 @@ class UpperTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerUPPER() + public function providerUPPER(): array { return require 'tests/data/Calculation/TextData/UPPER.php'; } @@ -51,7 +51,7 @@ class UpperTest extends TestCase Settings::setLocale('en_US'); } - public function providerLocaleLOWER() + public function providerLocaleLOWER(): array { return [ ['VRAI', 'fr_FR', true], diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php index 607c926b..b3ba1246 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ValueTest.php @@ -8,10 +8,19 @@ use PHPUnit\Framework\TestCase; class ValueTest extends TestCase { + /** + * @var string + */ private $currencyCode; + /** + * @var string + */ private $decimalSeparator; + /** + * @var string + */ private $thousandsSeparator; protected function setUp(): void @@ -44,7 +53,7 @@ class ValueTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerVALUE() + public function providerVALUE(): array { return require 'tests/data/Calculation/TextData/VALUE.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php index dfa01822..4e8335f1 100644 --- a/tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/FunctionsTest.php @@ -10,8 +10,14 @@ use PHPUnit\Framework\TestCase; class FunctionsTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; + /** + * @var string + */ private $returnDate; protected function setUp(): void @@ -123,7 +129,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsBlank() + public function providerIsBlank(): array { return require 'tests/data/Calculation/Functions/IS_BLANK.php'; } @@ -139,7 +145,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsErr() + public function providerIsErr(): array { return require 'tests/data/Calculation/Functions/IS_ERR.php'; } @@ -155,7 +161,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsError() + public function providerIsError(): array { return require 'tests/data/Calculation/Functions/IS_ERROR.php'; } @@ -171,7 +177,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerErrorType() + public function providerErrorType(): array { return require 'tests/data/Calculation/Functions/ERROR_TYPE.php'; } @@ -187,7 +193,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsLogical() + public function providerIsLogical(): array { return require 'tests/data/Calculation/Functions/IS_LOGICAL.php'; } @@ -203,7 +209,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsNa() + public function providerIsNa(): array { return require 'tests/data/Calculation/Functions/IS_NA.php'; } @@ -219,7 +225,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsNumber() + public function providerIsNumber(): array { return require 'tests/data/Calculation/Functions/IS_NUMBER.php'; } @@ -235,7 +241,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsText() + public function providerIsText(): array { return require 'tests/data/Calculation/Functions/IS_TEXT.php'; } @@ -251,7 +257,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsNonText() + public function providerIsNonText(): array { return require 'tests/data/Calculation/Functions/IS_NONTEXT.php'; } @@ -267,7 +273,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsEven() + public function providerIsEven(): array { return require 'tests/data/Calculation/Functions/IS_EVEN.php'; } @@ -283,7 +289,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsOdd() + public function providerIsOdd(): array { return require 'tests/data/Calculation/Functions/IS_ODD.php'; } @@ -299,7 +305,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerTYPE() + public function providerTYPE(): array { return require 'tests/data/Calculation/Functions/TYPE.php'; } @@ -315,7 +321,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerN() + public function providerN(): array { return require 'tests/data/Calculation/Functions/N.php'; } @@ -368,7 +374,7 @@ class FunctionsTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerIsFormula() + public function providerIsFormula(): array { return require 'tests/data/Calculation/Functions/ISFORMULA.php'; } @@ -384,7 +390,7 @@ class FunctionsTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerIfCondition() + public function providerIfCondition(): array { return require 'tests/data/Calculation/Functions/IF_CONDITION.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php b/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php index 6d603722..af8b8079 100644 --- a/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/LookupRefTest.php @@ -69,7 +69,7 @@ class LookupRefTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } - public function providerFormulaText() + public function providerFormulaText(): array { return require 'tests/data/Calculation/LookupRef/FORMULATEXT.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php b/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php index 1eb66a0a..e2384460 100644 --- a/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/TranslationTest.php @@ -9,8 +9,14 @@ use PHPUnit\Framework\TestCase; class TranslationTest extends TestCase { + /** + * @var string + */ private $compatibilityMode; + /** + * @var string + */ private $returnDate; protected function setUp(): void @@ -44,7 +50,7 @@ class TranslationTest extends TestCase self::assertSame($formula, $restoredFormula); } - public function providerTranslations() + public function providerTranslations(): array { return require 'tests/data/Calculation/Translations.php'; } diff --git a/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php b/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php index ea20fbf3..f8f02f0e 100644 --- a/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php @@ -75,7 +75,7 @@ class XlfnFunctionsTest extends \PHPUnit\Framework\TestCase $sheet->setSelectedCell('B1'); $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($workbook, 'Xlsx'); - $oufil = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $oufil = File::temporaryFilename(); $writer->save($oufil); $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx'); diff --git a/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php b/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php index ffe0e05f..3f9c8302 100644 --- a/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AddressHelperTest.php @@ -18,7 +18,7 @@ class AddressHelperTest extends TestCase self::assertSame($expectedValue, $actualValue); } - public function providerR1C1ConversionToA1Absolute() + public function providerR1C1ConversionToA1Absolute(): array { return require 'tests/data/Cell/R1C1ConversionToA1Absolute.php'; } @@ -45,7 +45,7 @@ class AddressHelperTest extends TestCase self::assertSame($expectedValue, $actualValue); } - public function providerR1C1ConversionToA1Relative() + public function providerR1C1ConversionToA1Relative(): array { return require 'tests/data/Cell/R1C1ConversionToA1Relative.php'; } @@ -60,7 +60,7 @@ class AddressHelperTest extends TestCase AddressHelper::convertToA1($address); } - public function providerR1C1ConversionToA1Exception() + public function providerR1C1ConversionToA1Exception(): array { return require 'tests/data/Cell/R1C1ConversionToA1Exception.php'; } @@ -75,7 +75,7 @@ class AddressHelperTest extends TestCase self::assertSame($expectedValue, $actualValue); } - public function providerA1ConversionToR1C1Absolute() + public function providerA1ConversionToR1C1Absolute(): array { return require 'tests/data/Cell/A1ConversionToR1C1Absolute.php'; } @@ -90,7 +90,7 @@ class AddressHelperTest extends TestCase self::assertSame($expectedValue, $actualValue); } - public function providerA1ConversionToR1C1Relative() + public function providerA1ConversionToR1C1Relative(): array { return require 'tests/data/Cell/A1ConversionToR1C1Relative.php'; } @@ -105,7 +105,7 @@ class AddressHelperTest extends TestCase AddressHelper::convertToR1C1($address); } - public function providerA1ConversionToR1C1Exception() + public function providerA1ConversionToR1C1Exception(): array { return require 'tests/data/Cell/A1ConversionToR1C1Exception.php'; } diff --git a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php index a524a15c..7b4bbb42 100644 --- a/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/AdvancedValueBinderTest.php @@ -13,10 +13,19 @@ use PHPUnit\Framework\TestCase; class AdvancedValueBinderTest extends TestCase { + /** + * @var string + */ private $currencyCode; + /** + * @var string + */ private $decimalSeparator; + /** + * @var string + */ private $thousandsSeparator; protected function setUp(): void @@ -59,9 +68,11 @@ class AdvancedValueBinderTest extends TestCase $sheet->expects(self::once()) ->method('getStyle') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('getNumberFormat') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('setFormatCode') ->with($format) @@ -81,7 +92,7 @@ class AdvancedValueBinderTest extends TestCase self::assertEquals($valueBinded, $cell->getValue()); } - public function currencyProvider() + public function currencyProvider(): array { $currencyUSD = NumberFormat::FORMAT_CURRENCY_USD_SIMPLE; $currencyEURO = str_replace('$', '€', NumberFormat::FORMAT_CURRENCY_USD_SIMPLE); @@ -121,9 +132,11 @@ class AdvancedValueBinderTest extends TestCase $sheet->expects(self::once()) ->method('getStyle') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('getNumberFormat') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('setFormatCode') ->with($format) @@ -139,7 +152,7 @@ class AdvancedValueBinderTest extends TestCase self::assertEquals($valueBinded, $cell->getValue()); } - public function fractionProvider() + public function fractionProvider(): array { return [ ['1/5', 0.2, '?/?'], @@ -179,9 +192,11 @@ class AdvancedValueBinderTest extends TestCase $sheet->expects(self::once()) ->method('getStyle') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('getNumberFormat') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('setFormatCode') ->with($format) @@ -197,7 +212,7 @@ class AdvancedValueBinderTest extends TestCase self::assertEquals($valueBinded, $cell->getValue()); } - public function percentageProvider() + public function percentageProvider(): array { return [ ['10%', 0.1, NumberFormat::FORMAT_PERCENTAGE_00], @@ -231,9 +246,11 @@ class AdvancedValueBinderTest extends TestCase $sheet->expects(self::once()) ->method('getStyle') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('getNumberFormat') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects(self::once()) ->method('setFormatCode') ->with($format) @@ -249,7 +266,7 @@ class AdvancedValueBinderTest extends TestCase self::assertEquals($valueBinded, $cell->getValue()); } - public function timeProvider() + public function timeProvider(): array { return [ ['1:20', 0.05555555556, NumberFormat::FORMAT_DATE_TIME3], @@ -279,9 +296,11 @@ class AdvancedValueBinderTest extends TestCase $sheet->expects($wrapped ? self::once() : self::never()) ->method('getStyle') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects($wrapped ? self::once() : self::never()) ->method('getAlignment') ->willReturnSelf(); + // @phpstan-ignore-next-line $sheet->expects($wrapped ? self::once() : self::never()) ->method('setWrapText') ->with($wrapped) @@ -296,7 +315,7 @@ class AdvancedValueBinderTest extends TestCase $binder->bindValue($cell, $value); } - public function stringProvider() + public function stringProvider(): array { return [ ['Hello World', false], diff --git a/tests/PhpSpreadsheetTests/Cell/CellTest.php b/tests/PhpSpreadsheetTests/Cell/CellTest.php index 0d9ce337..980f0170 100644 --- a/tests/PhpSpreadsheetTests/Cell/CellTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CellTest.php @@ -23,7 +23,7 @@ class CellTest extends TestCase self::assertSame($expected, $cell->getValue()); } - public function providerSetValueExplicit() + public function providerSetValueExplicit(): array { return require 'tests/data/Cell/SetValueExplicit.php'; } @@ -42,7 +42,7 @@ class CellTest extends TestCase $cell->setValueExplicit($value, $dataType); } - public function providerSetValueExplicitException() + public function providerSetValueExplicitException(): array { return require 'tests/data/Cell/SetValueExplicitException.php'; } diff --git a/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php b/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php index 9225b818..9a0a2c21 100644 --- a/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php +++ b/tests/PhpSpreadsheetTests/Cell/CoordinateTest.php @@ -24,7 +24,7 @@ class CoordinateTest extends TestCase self::assertEquals($stringBack, $string, 'should be able to get the original input with opposite method'); } - public function providerColumnString() + public function providerColumnString(): array { return require 'tests/data/ColumnString.php'; } @@ -74,7 +74,7 @@ class CoordinateTest extends TestCase self::assertEquals($columnIndexBack, $columnIndex, 'should be able to get the original input with opposite method'); } - public function providerColumnIndex() + public function providerColumnIndex(): array { return require 'tests/data/ColumnIndex.php'; } @@ -91,7 +91,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCoordinates() + public function providerCoordinates(): array { return require 'tests/data/CellCoordinates.php'; } @@ -167,7 +167,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerAbsoluteCoordinates() + public function providerAbsoluteCoordinates(): array { return require 'tests/data/CellAbsoluteCoordinate.php'; } @@ -199,7 +199,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerAbsoluteReferences() + public function providerAbsoluteReferences(): array { return require 'tests/data/CellAbsoluteReference.php'; } @@ -237,7 +237,7 @@ class CoordinateTest extends TestCase } } - public function providerSplitRange() + public function providerSplitRange(): array { return require 'tests/data/CellSplitRange.php'; } @@ -254,7 +254,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerBuildRange() + public function providerBuildRange(): array { return require 'tests/data/CellBuildRange.php'; } @@ -264,6 +264,7 @@ class CoordinateTest extends TestCase $this->expectException(TypeError::class); $cellRange = null; + // @phpstan-ignore-next-line Coordinate::buildRange($cellRange); } @@ -288,7 +289,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerRangeBoundaries() + public function providerRangeBoundaries(): array { return require 'tests/data/CellRangeBoundaries.php'; } @@ -305,7 +306,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerRangeDimension() + public function providerRangeDimension(): array { return require 'tests/data/CellRangeDimension.php'; } @@ -322,7 +323,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerGetRangeBoundaries() + public function providerGetRangeBoundaries(): array { return require 'tests/data/CellGetRangeBoundaries.php'; } @@ -339,7 +340,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerExtractAllCellReferencesInRange() + public function providerExtractAllCellReferencesInRange(): array { return require 'tests/data/CellExtractAllCellReferencesInRange.php'; } @@ -357,7 +358,7 @@ class CoordinateTest extends TestCase Coordinate::extractAllCellReferencesInRange($range); } - public function providerInvalidRange() + public function providerInvalidRange(): array { return [['Z1:A1'], ['A4:A1'], ['B1:A1'], ['AA1:Z1']]; } @@ -374,7 +375,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerMergeRangesInCollection() + public function providerMergeRangesInCollection(): array { return require 'tests/data/CellMergeRangesInCollection.php'; } @@ -391,7 +392,7 @@ class CoordinateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCoordinateIsRange() + public function providerCoordinateIsRange(): array { return require 'tests/data/CoordinateIsRange.php'; } diff --git a/tests/PhpSpreadsheetTests/Cell/DataTypeTest.php b/tests/PhpSpreadsheetTests/Cell/DataTypeTest.php index 95454c16..176dd6ac 100644 --- a/tests/PhpSpreadsheetTests/Cell/DataTypeTest.php +++ b/tests/PhpSpreadsheetTests/Cell/DataTypeTest.php @@ -25,6 +25,7 @@ class DataTypeTest extends TestCase $stringLimit = 32767; $randString = $this->randr($stringLimit + 10); $result2 = DataType::checkString($randString); + self::assertIsString($result2); self::assertSame($stringLimit, strlen($result2)); $dirtyString = "bla bla\r\n bla\r test\n"; diff --git a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php index d85de161..cc9098bf 100644 --- a/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php +++ b/tests/PhpSpreadsheetTests/Cell/DefaultValueBinderTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\TestCase; class DefaultValueBinderTest extends TestCase { - private function createCellStub() + private function createCellStub(): Cell { // Create a stub for the Cell class. /** @var Cell&MockObject $cellStub */ @@ -42,7 +42,7 @@ class DefaultValueBinderTest extends TestCase self::assertTrue($result); } - public function binderProvider() + public function binderProvider(): array { return [ [null], @@ -74,7 +74,7 @@ class DefaultValueBinderTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDataTypeForValue() + public function providerDataTypeForValue(): array { return require 'tests/data/Cell/DefaultValueBinder.php'; } diff --git a/tests/PhpSpreadsheetTests/Cell/HyperlinkTest.php b/tests/PhpSpreadsheetTests/Cell/HyperlinkTest.php index 9c09aa75..e92fbaf3 100644 --- a/tests/PhpSpreadsheetTests/Cell/HyperlinkTest.php +++ b/tests/PhpSpreadsheetTests/Cell/HyperlinkTest.php @@ -34,7 +34,7 @@ class HyperlinkTest extends TestCase { $tooltipValue = 'PhpSpreadsheet Web Site'; - $testInstance = new Hyperlink(null, $tooltipValue); + $testInstance = new Hyperlink('', $tooltipValue); $result = $testInstance->getTooltip(); self::assertEquals($tooltipValue, $result); @@ -45,7 +45,7 @@ class HyperlinkTest extends TestCase $initialTooltipValue = 'PhpSpreadsheet Web Site'; $newTooltipValue = 'PhpSpreadsheet Repository on Github'; - $testInstance = new Hyperlink(null, $initialTooltipValue); + $testInstance = new Hyperlink('', $initialTooltipValue); $result = $testInstance->setTooltip($newTooltipValue); self::assertInstanceOf(Hyperlink::class, $result); diff --git a/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php b/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php index 830e712a..e2ddc602 100644 --- a/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php +++ b/tests/PhpSpreadsheetTests/Cell/ValueBinderWithOverriddenDataTypeForValue.php @@ -6,6 +6,9 @@ use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder; class ValueBinderWithOverriddenDataTypeForValue extends DefaultValueBinder { + /** + * @var bool + */ public static $called = false; public static function dataTypeForValue($value) diff --git a/tests/PhpSpreadsheetTests/Chart/LegendTest.php b/tests/PhpSpreadsheetTests/Chart/LegendTest.php index 30715365..b12658a4 100644 --- a/tests/PhpSpreadsheetTests/Chart/LegendTest.php +++ b/tests/PhpSpreadsheetTests/Chart/LegendTest.php @@ -98,22 +98,11 @@ class LegendTest extends TestCase $testInstance = new Legend(); foreach ($overlayValues as $overlayValue) { - $result = $testInstance->setOverlay($overlayValue); - self::assertTrue($result); + $testInstance->setOverlay($overlayValue); + self::assertSame($overlayValue, $testInstance->getOverlay()); } } - public function testSetInvalidOverlayReturnsFalse(): void - { - $testInstance = new Legend(); - - $result = $testInstance->setOverlay('INVALID'); - self::assertFalse($result); - - $result = $testInstance->getOverlay(); - self::assertFalse($result); - } - public function testGetOverlay(): void { $OverlayValue = true; diff --git a/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php b/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php index 4d1025d2..828329ac 100644 --- a/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php +++ b/tests/PhpSpreadsheetTests/Custom/ComplexAssert.php @@ -6,9 +6,16 @@ use Complex\Complex; class ComplexAssert { + /** + * @var string + */ private $errorMessage = ''; - private function testExpectedExceptions($expected, $actual) + /** + * @param mixed $expected + * @param mixed $actual + */ + private function testExpectedExceptions($expected, $actual): bool { // Expecting an error, so we do a straight string comparison if ($expected === $actual) { @@ -21,7 +28,7 @@ class ComplexAssert return false; } - private function adjustDelta($expected, $actual, $delta) + private function adjustDelta(float $expected, float $actual, float $delta): float { $adjustedDelta = $delta; @@ -33,7 +40,11 @@ class ComplexAssert return $adjustedDelta > 1.0 ? 1.0 : $adjustedDelta; } - public function assertComplexEquals($expected, $actual, $delta = 0) + /** + * @param mixed $expected + * @param mixed $actual + */ + public function assertComplexEquals($expected, $actual, float $delta = 0): bool { if ($expected === INF || (is_string($expected) && $expected[0] === '#')) { return $this->testExpectedExceptions($expected, $actual); @@ -42,16 +53,6 @@ class ComplexAssert $expectedComplex = new Complex($expected); $actualComplex = new Complex($actual); - if (!is_numeric($actualComplex->getReal()) || !is_numeric($expectedComplex->getReal())) { - if ($actualComplex->getReal() !== $expectedComplex->getReal()) { - $this->errorMessage = 'Mismatched String: ' . $actualComplex->getReal() . ' !== ' . $expectedComplex->getReal(); - - return false; - } - - return true; - } - $adjustedDelta = $this->adjustDelta($expectedComplex->getReal(), $actualComplex->getReal(), $delta); if (abs($actualComplex->getReal() - $expectedComplex->getReal()) > $adjustedDelta) { $this->errorMessage = 'Mismatched Real part: ' . $actualComplex->getReal() . ' != ' . $expectedComplex->getReal(); @@ -75,7 +76,7 @@ class ComplexAssert return true; } - public function getErrorMessage() + public function getErrorMessage(): string { return $this->errorMessage; } diff --git a/tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php b/tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php index 14843091..4b17230e 100644 --- a/tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php +++ b/tests/PhpSpreadsheetTests/DefinedNameFormulaTest.php @@ -31,7 +31,7 @@ class DefinedNameFormulaTest extends TestCase } $allDefinedNames = $spreadSheet->getDefinedNames(); - self::assertSame(count($definedNamesForTest), count($allDefinedNames)); + self::assertCount(count($definedNamesForTest), $allDefinedNames); } public function testGetNamedRanges(): void @@ -49,7 +49,7 @@ class DefinedNameFormulaTest extends TestCase } $allNamedRanges = $spreadSheet->getNamedRanges(); - self::assertSame(count(array_filter($rangeOrFormula)), count($allNamedRanges)); + self::assertCount(count(array_filter($rangeOrFormula)), $allNamedRanges); } public function testGetScopedNamedRange(): void @@ -65,6 +65,7 @@ class DefinedNameFormulaTest extends TestCase $spreadSheet->addDefinedName(DefinedName::createInstance($rangeName, $workSheet, $localRangeValue, true)); $localScopedRange = $spreadSheet->getNamedRange($rangeName, $workSheet); + self::assertNotNull($localScopedRange); self::assertSame($localRangeValue, $localScopedRange->getValue()); } @@ -83,6 +84,7 @@ class DefinedNameFormulaTest extends TestCase $spreadSheet->addDefinedName(DefinedName::createInstance($rangeName, $workSheet1, $localRangeValue, true)); $localScopedRange = $spreadSheet->getNamedRange($rangeName, $workSheet2); + self::assertNotNull($localScopedRange); self::assertSame($globalRangeValue, $localScopedRange->getValue()); } @@ -101,7 +103,7 @@ class DefinedNameFormulaTest extends TestCase } $allNamedFormulae = $spreadSheet->getNamedFormulae(); - self::assertSame(count(array_filter($rangeOrFormula)), count($allNamedFormulae)); + self::assertCount(count(array_filter($rangeOrFormula)), $allNamedFormulae); } public function testGetScopedNamedFormula(): void @@ -117,6 +119,7 @@ class DefinedNameFormulaTest extends TestCase $spreadSheet->addDefinedName(DefinedName::createInstance($formulaName, $workSheet, $localFormulaValue, true)); $localScopedFormula = $spreadSheet->getNamedFormula($formulaName, $workSheet); + self::assertNotNull($localScopedFormula); self::assertSame($localFormulaValue, $localScopedFormula->getValue()); } @@ -135,6 +138,7 @@ class DefinedNameFormulaTest extends TestCase $spreadSheet->addDefinedName(DefinedName::createInstance($formulaName, $workSheet1, $localFormulaValue, true)); $localScopedFormula = $spreadSheet->getNamedFormula($formulaName, $workSheet2); + self::assertNotNull($localScopedFormula); self::assertSame($globalFormulaValue, $localScopedFormula->getValue()); } diff --git a/tests/PhpSpreadsheetTests/DefinedNameTest.php b/tests/PhpSpreadsheetTests/DefinedNameTest.php index 4d877e6f..43eddc8a 100644 --- a/tests/PhpSpreadsheetTests/DefinedNameTest.php +++ b/tests/PhpSpreadsheetTests/DefinedNameTest.php @@ -47,10 +47,9 @@ class DefinedNameTest extends TestCase ); self::assertCount(1, $this->spreadsheet->getDefinedNames()); - self::assertSame( - '=B1', - $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getActiveSheet())->getValue() - ); + $definedName = $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getActiveSheet()); + self::assertNotNull($definedName); + self::assertSame('=B1', $definedName->getValue()); } public function testAddScopedDefinedNameWithSameName(): void @@ -63,14 +62,13 @@ class DefinedNameTest extends TestCase ); self::assertCount(2, $this->spreadsheet->getDefinedNames()); - self::assertSame( - '=A1', - $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getActiveSheet())->getValue() - ); - self::assertSame( - '=B1', - $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getSheetByName('Sheet #2'))->getValue() - ); + $definedName1 = $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getActiveSheet()); + self::assertNotNull($definedName1); + self::assertSame('=A1', $definedName1->getValue()); + + $definedName2 = $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getSheetByName('Sheet #2')); + self::assertNotNull($definedName2); + self::assertSame('=B1', $definedName2->getValue()); } public function testRemoveDefinedName(): void @@ -99,10 +97,9 @@ class DefinedNameTest extends TestCase $this->spreadsheet->removeDefinedName('Foo', $this->spreadsheet->getActiveSheet()); self::assertCount(1, $this->spreadsheet->getDefinedNames()); - self::assertSame( - '=B1', - $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getSheetByName('Sheet #2'))->getValue() - ); + $definedName = $this->spreadsheet->getDefinedName('foo', $this->spreadsheet->getSheetByName('Sheet #2')); + self::assertNotNull($definedName); + self::assertSame('=B1', $definedName->getValue()); } public function testRemoveScopedDefinedNameWhenDuplicateNames(): void @@ -117,10 +114,9 @@ class DefinedNameTest extends TestCase $this->spreadsheet->removeDefinedName('Foo', $this->spreadsheet->getSheetByName('Sheet #2')); self::assertCount(1, $this->spreadsheet->getDefinedNames()); - self::assertSame( - '=A1', - $this->spreadsheet->getDefinedName('foo')->getValue() - ); + $definedName = $this->spreadsheet->getDefinedName('foo'); + self::assertNotNull($definedName); + self::assertSame('=A1', $definedName->getValue()); } public function testDefinedNameNoWorksheetNoScope(): void @@ -148,6 +144,9 @@ class DefinedNameTest extends TestCase { $sheet1 = $this->spreadsheet->getSheetByName('Sheet #1'); $sheet2 = $this->spreadsheet->getSheetByName('Sheet #2'); + self::assertNotNull($sheet1); + self::assertNotNull($sheet2); + $sheet1->getCell('A1')->setValue(1); $sheet2->getCell('A1')->setValue(2); $namedRange = new NamedRange('xyz', $sheet2, '$A$1'); @@ -163,6 +162,9 @@ class DefinedNameTest extends TestCase { $sheet1 = $this->spreadsheet->getSheetByName('Sheet #1'); $sheet2 = $this->spreadsheet->getSheetByName('Sheet #2'); + self::assertNotNull($sheet1); + self::assertNotNull($sheet2); + $sheet1->getCell('A1')->setValue(1); $sheet2->getCell('A1')->setValue(2); $namedRange = new NamedRange('abc', $sheet2, '$A$1'); @@ -178,6 +180,9 @@ class DefinedNameTest extends TestCase { $sheet1 = $this->spreadsheet->getSheetByName('Sheet #1'); $sheet2 = $this->spreadsheet->getSheetByName('Sheet #2'); + self::assertNotNull($sheet1); + self::assertNotNull($sheet2); + $sheet1->getCell('A1')->setValue(1); $sheet2->getCell('A1')->setValue(2); $namedRange = new NamedRange('abc', $sheet2, '$A$1'); @@ -193,12 +198,17 @@ class DefinedNameTest extends TestCase { $sheet1 = $this->spreadsheet->getSheetByName('Sheet #1'); $sheet2 = $this->spreadsheet->getSheetByName('Sheet #2'); + self::assertNotNull($sheet1); + self::assertNotNull($sheet2); + $sheet1->getCell('A1')->setValue(1); $sheet2->getCell('A1')->setValue(2); $namedRange = new NamedRange('abc', $sheet2, '$A$1'); $namedRangeClone = clone $namedRange; $ss1 = $namedRange->getWorksheet(); $ss2 = $namedRangeClone->getWorksheet(); + self::assertNotNull($ss1); + self::assertNotNull($ss2); self::assertNotSame($ss1, $ss2); self::assertEquals($ss1->getTitle(), $ss2->getTitle()); } diff --git a/tests/PhpSpreadsheetTests/Document/PropertiesTest.php b/tests/PhpSpreadsheetTests/Document/PropertiesTest.php index 567cf620..54932bb8 100644 --- a/tests/PhpSpreadsheetTests/Document/PropertiesTest.php +++ b/tests/PhpSpreadsheetTests/Document/PropertiesTest.php @@ -7,7 +7,10 @@ use PHPUnit\Framework\TestCase; class PropertiesTest extends TestCase { - protected $properties; + /** + * @var Properties + */ + private $properties; protected function setup(): void { diff --git a/tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php b/tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php index f242c698..da821532 100644 --- a/tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php +++ b/tests/PhpSpreadsheetTests/Functional/AbstractFunctional.php @@ -21,7 +21,7 @@ abstract class AbstractFunctional extends TestCase */ protected function writeAndReload(Spreadsheet $spreadsheet, $format, ?callable $readerCustomizer = null) { - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer = IOFactory::createWriter($spreadsheet, $format); $writer->save($filename); diff --git a/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php b/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php index ef7d9fb4..024185c6 100644 --- a/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Style\Protection; class ActiveSheetTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xls'], diff --git a/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php b/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php index 045cdcd5..38117059 100644 --- a/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ColumnWidthTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class ColumnWidthTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xlsx'], diff --git a/tests/PhpSpreadsheetTests/Functional/CommentsTest.php b/tests/PhpSpreadsheetTests/Functional/CommentsTest.php index 2b08c9a6..d82f7f96 100644 --- a/tests/PhpSpreadsheetTests/Functional/CommentsTest.php +++ b/tests/PhpSpreadsheetTests/Functional/CommentsTest.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Style\Alignment; class CommentsTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Html'], diff --git a/tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php b/tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php index 3183450f..5ee0b1f5 100644 --- a/tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php @@ -9,7 +9,7 @@ class ConditionalStopIfTrueTest extends AbstractFunctional const COLOR_GREEN = 'FF99FF66'; const COLOR_RED = 'FFFF5050'; - public function providerFormats() + public function providerFormats(): array { return [ ['Xlsx'], diff --git a/tests/PhpSpreadsheetTests/Functional/EnclosureTest.php b/tests/PhpSpreadsheetTests/Functional/EnclosureTest.php index 1f1cb7eb..2ddecfd2 100644 --- a/tests/PhpSpreadsheetTests/Functional/EnclosureTest.php +++ b/tests/PhpSpreadsheetTests/Functional/EnclosureTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class EnclosureTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Html'], diff --git a/tests/PhpSpreadsheetTests/Functional/FreezePaneTest.php b/tests/PhpSpreadsheetTests/Functional/FreezePaneTest.php index 4e725d03..67083949 100644 --- a/tests/PhpSpreadsheetTests/Functional/FreezePaneTest.php +++ b/tests/PhpSpreadsheetTests/Functional/FreezePaneTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class FreezePaneTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xls'], diff --git a/tests/PhpSpreadsheetTests/Functional/MergedCellsTest.php b/tests/PhpSpreadsheetTests/Functional/MergedCellsTest.php index 39865817..d2e9234f 100644 --- a/tests/PhpSpreadsheetTests/Functional/MergedCellsTest.php +++ b/tests/PhpSpreadsheetTests/Functional/MergedCellsTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class MergedCellsTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Html'], diff --git a/tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php b/tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php index 584f6dd5..93753762 100644 --- a/tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php +++ b/tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class PrintAreaTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xls'], diff --git a/tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php b/tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php index 9dac3437..585871dc 100644 --- a/tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class ReadBlankCellsTest extends AbstractFunctional { - public function providerSheetFormat() + public function providerSheetFormat(): array { return [ ['Xlsx'], diff --git a/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php b/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php index 9ab86baa..930288a7 100644 --- a/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php +++ b/tests/PhpSpreadsheetTests/Functional/ReadFilterTest.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class ReadFilterTest extends AbstractFunctional { - public function providerCellsValues() + public function providerCellsValues(): array { $cellValues = [ // one argument as a multidimensional array diff --git a/tests/PhpSpreadsheetTests/Functional/SelectedCellsTest.php b/tests/PhpSpreadsheetTests/Functional/SelectedCellsTest.php index 625f2428..a1866b09 100644 --- a/tests/PhpSpreadsheetTests/Functional/SelectedCellsTest.php +++ b/tests/PhpSpreadsheetTests/Functional/SelectedCellsTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class SelectedCellsTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xls'], diff --git a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php index e6d6377b..bebf0589 100644 --- a/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php +++ b/tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class TypeAttributePreservationTest extends AbstractFunctional { - public function providerFormulae() + public function providerFormulae(): array { $formats = ['Xlsx']; $data = require 'tests/data/Functional/TypeAttributePreservation/Formula.php'; diff --git a/tests/PhpSpreadsheetTests/Functional/WorkbookViewAttributesTest.php b/tests/PhpSpreadsheetTests/Functional/WorkbookViewAttributesTest.php index f97ad9cf..8d44c4d2 100644 --- a/tests/PhpSpreadsheetTests/Functional/WorkbookViewAttributesTest.php +++ b/tests/PhpSpreadsheetTests/Functional/WorkbookViewAttributesTest.php @@ -6,7 +6,7 @@ use PhpOffice\PhpSpreadsheet\Spreadsheet; class WorkbookViewAttributesTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xlsx'], diff --git a/tests/PhpSpreadsheetTests/Helper/HtmlTest.php b/tests/PhpSpreadsheetTests/Helper/HtmlTest.php index d47c2f64..b2fadf42 100644 --- a/tests/PhpSpreadsheetTests/Helper/HtmlTest.php +++ b/tests/PhpSpreadsheetTests/Helper/HtmlTest.php @@ -21,7 +21,7 @@ class HtmlTest extends TestCase self::assertSame($expected, $actual->getPlainText()); } - public function providerUtf8EncodingSupport() + public function providerUtf8EncodingSupport(): array { return [ ['foo', 'foo'], diff --git a/tests/PhpSpreadsheetTests/Helper/SampleTest.php b/tests/PhpSpreadsheetTests/Helper/SampleTest.php index 8956771c..0817f1d5 100644 --- a/tests/PhpSpreadsheetTests/Helper/SampleTest.php +++ b/tests/PhpSpreadsheetTests/Helper/SampleTest.php @@ -25,7 +25,7 @@ class SampleTest extends TestCase self::assertTrue(true); } - public function providerSample() + public function providerSample(): array { $skipped = [ 'Chart/32_Chart_read_write_PDF.php', // Unfortunately JpGraph is not up to date for latest PHP and raise many warnings diff --git a/tests/PhpSpreadsheetTests/IOFactoryTest.php b/tests/PhpSpreadsheetTests/IOFactoryTest.php index 886fcb36..4837d6cf 100644 --- a/tests/PhpSpreadsheetTests/IOFactoryTest.php +++ b/tests/PhpSpreadsheetTests/IOFactoryTest.php @@ -24,7 +24,7 @@ class IOFactoryTest extends TestCase self::assertInstanceOf($expected, $actual); } - public function providerCreateWriter() + public function providerCreateWriter(): array { return [ ['Xls', Writer\Xls::class], @@ -58,7 +58,7 @@ class IOFactoryTest extends TestCase self::assertInstanceOf($expected, $actual); } - public function providerCreateReader() + public function providerCreateReader(): array { return [ ['Xls', Reader\Xls::class], @@ -118,7 +118,7 @@ class IOFactoryTest extends TestCase self::assertInstanceOf(Spreadsheet::class, $actual); } - public function providerIdentify() + public function providerIdentify(): array { return [ ['samples/templates/26template.xlsx', 'Xlsx', Reader\Xlsx::class], diff --git a/tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php b/tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php index 9bc16ae0..1abe9940 100644 --- a/tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php +++ b/tests/PhpSpreadsheetTests/Reader/CsvContiguousFilter.php @@ -7,10 +7,19 @@ use PhpOffice\PhpSpreadsheet\Reader\IReadFilter; /** Define a Read Filter class implementing IReadFilter */ class CsvContiguousFilter implements IReadFilter { + /** + * @var int + */ private $startRow = 0; + /** + * @var int + */ private $endRow = 0; + /** + * @var int + */ private $filterType = 0; /** diff --git a/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php b/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php index 176e3b75..82f960e4 100644 --- a/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php +++ b/tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php @@ -8,6 +8,9 @@ use PHPUnit\Framework\TestCase; class CsvContiguousTest extends TestCase { + /** + * @var string + */ private $inputFileName = 'samples/Reader/sampleData/example2.csv'; public function testContiguous(): void diff --git a/tests/PhpSpreadsheetTests/Reader/CsvTest.php b/tests/PhpSpreadsheetTests/Reader/CsvTest.php index e543ff48..73c281ec 100644 --- a/tests/PhpSpreadsheetTests/Reader/CsvTest.php +++ b/tests/PhpSpreadsheetTests/Reader/CsvTest.php @@ -29,7 +29,7 @@ class CsvTest extends TestCase self::assertSame($expectedValue, $actual, 'should be able to retrieve correct value'); } - public function providerDelimiterDetection() + public function providerDelimiterDetection(): array { return [ [ @@ -101,7 +101,7 @@ class CsvTest extends TestCase self::assertSame($expected, $reader->canRead($filename)); } - public function providerCanLoad() + public function providerCanLoad(): array { return [ [false, 'tests/data/Reader/Ods/data.ods'], @@ -172,7 +172,7 @@ class CsvTest extends TestCase self::assertEquals(2, $info[0]['totalColumns']); } - public function providerEncodings() + public function providerEncodings(): array { return [ ['tests/data/Reader/CSV/encoding.iso88591.csv', 'ISO-8859-1'], @@ -288,7 +288,7 @@ EOF; self::assertEquals($delimiter, $reader->getDelimiter()); } - public function providerEscapes() + public function providerEscapes(): array { return [ ['\\', ';'], @@ -310,7 +310,7 @@ EOF; self::assertEquals('sixième', $sheet->getCell('C2')->getValue()); } - public function providerGuessEncoding() + public function providerGuessEncoding(): array { return [ ['tests/data/Reader/CSV/premiere.utf8.csv'], diff --git a/tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php b/tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php index c09902ff..a6be40c9 100644 --- a/tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php +++ b/tests/PhpSpreadsheetTests/Reader/Html/HtmlHelper.php @@ -3,13 +3,14 @@ namespace PhpOffice\PhpSpreadsheetTests\Reader\Html; use PhpOffice\PhpSpreadsheet\Reader\Html; +use PhpOffice\PhpSpreadsheet\Shared\File; use PhpOffice\PhpSpreadsheet\Spreadsheet; class HtmlHelper { public static function createHtml(string $html): string { - $filename = tempnam(sys_get_temp_dir(), 'html'); + $filename = File::temporaryFilename(); file_put_contents($filename, $html); return $filename; diff --git a/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php b/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php index 14bdb39a..7acc5527 100644 --- a/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php @@ -20,22 +20,22 @@ class HtmlTest extends TestCase public function testBadHtml(): void { - $this->expectException(ReaderException::class); $filename = 'tests/data/Reader/HTML/badhtml.html'; $reader = new Html(); self::assertTrue($reader->canRead($filename)); + + $this->expectException(ReaderException::class); $reader->load($filename); - self::assertTrue(false); } public function testNonHtml(): void { - $this->expectException(ReaderException::class); $filename = __FILE__; $reader = new Html(); self::assertFalse($reader->canRead($filename)); + + $this->expectException(ReaderException::class); $reader->load($filename); - self::assertTrue(false); } public function testInvalidFilename(): void @@ -45,7 +45,7 @@ class HtmlTest extends TestCase self::assertFalse($reader->canRead('')); } - public function providerCanReadVerySmallFile() + public function providerCanReadVerySmallFile(): array { $padding = str_repeat('a', 2048); diff --git a/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php b/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php index 2cc5377a..10910207 100644 --- a/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php @@ -15,6 +15,9 @@ use PHPUnit\Framework\TestCase; */ class OdsTest extends TestCase { + /** + * @var string + */ private $timeZone; protected function setUp(): void @@ -43,7 +46,7 @@ class OdsTest extends TestCase */ private function loadOdsTestFile() { - if (!$this->spreadsheetOdsTest) { + if (!isset($this->spreadsheetOdsTest)) { $filename = 'samples/templates/OOCalcTest.ods'; // Load into this instance @@ -59,7 +62,7 @@ class OdsTest extends TestCase */ protected function loadDataFile() { - if (!$this->spreadsheetData) { + if (!isset($this->spreadsheetData)) { $filename = 'tests/data/Reader/Ods/data.ods'; // Load into this instance diff --git a/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php b/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php index c434aa60..39bc864c 100644 --- a/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php @@ -41,7 +41,7 @@ class XmlScannerTest extends TestCase } } - public function providerValidXML() + public function providerValidXML(): array { $tests = []; foreach (glob('tests/data/Reader/Xml/XEETestValid*.xml') as $file) { @@ -78,7 +78,7 @@ class XmlScannerTest extends TestCase } } - public function providerInvalidXML() + public function providerInvalidXML(): array { $tests = []; foreach (glob('tests/data/Reader/Xml/XEETestInvalidUTF*.xml') as $file) { @@ -125,7 +125,7 @@ class XmlScannerTest extends TestCase self::assertEquals(strrev($expectedResult), $xml); } - public function providerValidXMLForCallback() + public function providerValidXMLForCallback(): array { $tests = []; foreach (glob('tests/data/Reader/Xml/SecurityScannerWithCallback*.xml') as $file) { diff --git a/tests/PhpSpreadsheetTests/Reader/SlkTest.php b/tests/PhpSpreadsheetTests/Reader/SlkTest.php index e461557e..6881648d 100644 --- a/tests/PhpSpreadsheetTests/Reader/SlkTest.php +++ b/tests/PhpSpreadsheetTests/Reader/SlkTest.php @@ -11,8 +11,14 @@ use PhpOffice\PhpSpreadsheet\Style\Font; class SlkTest extends \PHPUnit\Framework\TestCase { + /** + * @var string + */ private static $testbook = __DIR__ . '/../../../samples/templates/SylkTest.slk'; + /** + * @var string + */ private $filename = ''; protected function teardown(): void diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php index 63da2d05..7287b711 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/AutoFilterTest.php @@ -36,7 +36,7 @@ class AutoFilterTest extends TestCase return $instance; } - public function loadDataProvider() + public function loadDataProvider(): array { return [ ['$B3$E8', 0, 'B3E8'], diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php index 60c5440b..57fbdad2 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php @@ -31,7 +31,7 @@ class ConditionalFormattingDataBarXlsxTest extends TestCase { // Make sure conditionals from existing file are maintained across save $filename = 'tests/data/Reader/XLSX/conditionalFormattingDataBarTest.xlsx'; - $outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outfile = File::temporaryFilename(); $reader = IOFactory::createReader('Xlsx'); $spreadshee1 = $reader->load($filename); $writer = IOFactory::createWriter($spreadshee1, 'Xlsx'); @@ -49,7 +49,7 @@ class ConditionalFormattingDataBarXlsxTest extends TestCase public function testNewXlsxConditionalFormattingDataBar(): void { // Make sure blanks/non-blanks added by PhpSpreadsheet are handled correctly - $outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outfile = File::temporaryFilename(); $spreadshee1 = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); $sheet = $spreadshee1->getActiveSheet(); $sheet->setCellValue('A1', 1); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php index 1220c378..cef72121 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx2Test.php @@ -49,7 +49,7 @@ class Xlsx2Test extends TestCase { // Make sure conditionals from existing file are maintained across save $filename = 'tests/data/Reader/XLSX/conditionalFormatting2Test.xlsx'; - $outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outfile = File::temporaryFilename(); $reader = IOFactory::createReader('Xlsx'); $spreadshee1 = $reader->load($filename); $writer = IOFactory::createWriter($spreadshee1, 'Xlsx'); @@ -87,7 +87,7 @@ class Xlsx2Test extends TestCase public function testNewXlsxConditionalFormatting2(): void { // Make sure blanks/non-blanks added by PhpSpreadsheet are handled correctly - $outfile = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outfile = File::temporaryFilename(); $spreadshee1 = new \PhpOffice\PhpSpreadsheet\Spreadsheet(); $sheet = $spreadshee1->getActiveSheet(); $sheet->setCellValue('A2', 'a2'); diff --git a/tests/PhpSpreadsheetTests/Reader/XlsxTest.php b/tests/PhpSpreadsheetTests/Reader/XlsxTest.php index 1e240283..738a25b9 100644 --- a/tests/PhpSpreadsheetTests/Reader/XlsxTest.php +++ b/tests/PhpSpreadsheetTests/Reader/XlsxTest.php @@ -237,7 +237,7 @@ class XlsxTest extends TestCase $filename = 'tests/data/Reader/XLSX/empty_drawing.xlsx'; $reader = new Xlsx(); $excel = $reader->load($filename); - $resultFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $resultFilename = File::temporaryFilename(); $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($excel); $writer->save($resultFilename); $excel = $reader->load($resultFilename); @@ -258,7 +258,7 @@ class XlsxTest extends TestCase self::assertEquals(preg_match('/\s/', $string), 0); } - public function providerStripsWhiteSpaceFromStyleString() + public function providerStripsWhiteSpaceFromStyleString(): array { return [ ['position:absolute;margin-left:424.5pt;margin-top:169.5pt;width:67.5pt; diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php index e0b43113..8b9e05ff 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php @@ -8,6 +8,9 @@ use PHPUnit\Framework\TestCase; class XmlOddTest extends TestCase { + /** + * @var string + */ private $filename = ''; protected function teardown(): void @@ -53,7 +56,7 @@ class XmlOddTest extends TestCase EOT; - $this->filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $this->filename = File::temporaryFilename(); file_put_contents($this->filename, $xmldata); $reader = new Xml(); $spreadsheet = $reader->load($this->filename); diff --git a/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php b/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php index d53135f9..bcc108c1 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php @@ -19,7 +19,7 @@ class XmlTest extends TestCase $xmlReader->trySimpleXMLLoadString($filename); } - public function providerInvalidSimpleXML() + public function providerInvalidSimpleXML(): array { $tests = []; foreach (glob('tests/data/Reader/Xml/XEETestInvalidSimpleXML*.xml') as $file) { diff --git a/tests/PhpSpreadsheetTests/SettingsTest.php b/tests/PhpSpreadsheetTests/SettingsTest.php index 7641f3da..11b93ae6 100644 --- a/tests/PhpSpreadsheetTests/SettingsTest.php +++ b/tests/PhpSpreadsheetTests/SettingsTest.php @@ -10,7 +10,7 @@ class SettingsTest extends TestCase /** * @var bool */ - protected $prevValue; + private $prevValue; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Shared/CodePageTest.php b/tests/PhpSpreadsheetTests/Shared/CodePageTest.php index eb121889..e7dc7469 100644 --- a/tests/PhpSpreadsheetTests/Shared/CodePageTest.php +++ b/tests/PhpSpreadsheetTests/Shared/CodePageTest.php @@ -20,7 +20,7 @@ class CodePageTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCodePage() + public function providerCodePage(): array { return require 'tests/data/Shared/CodePage.php'; } diff --git a/tests/PhpSpreadsheetTests/Shared/DateTest.php b/tests/PhpSpreadsheetTests/Shared/DateTest.php index 4ab7461b..1ca4c674 100644 --- a/tests/PhpSpreadsheetTests/Shared/DateTest.php +++ b/tests/PhpSpreadsheetTests/Shared/DateTest.php @@ -2,14 +2,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Shared; +use DateTimeZone; use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Style\NumberFormat; use PHPUnit\Framework\TestCase; class DateTest extends TestCase { + /** + * @var int + */ private $excelCalendar; + /** + * @var null|DateTimeZone + */ private $dttimezone; protected function setUp(): void @@ -61,7 +68,7 @@ class DateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDateTimeExcelToTimestamp1900() + public function providerDateTimeExcelToTimestamp1900(): array { return require 'tests/data/Shared/Date/ExcelToTimestamp1900.php'; } @@ -80,7 +87,7 @@ class DateTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } - public function providerDateTimeTimestampToExcel1900() + public function providerDateTimeTimestampToExcel1900(): array { return require 'tests/data/Shared/Date/TimestampToExcel1900.php'; } @@ -99,7 +106,7 @@ class DateTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } - public function providerDateTimeDateTimeToExcel() + public function providerDateTimeDateTimeToExcel(): array { return require 'tests/data/Shared/Date/DateTimeToExcel.php'; } @@ -117,7 +124,7 @@ class DateTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } - public function providerDateTimeFormattedPHPToExcel1900() + public function providerDateTimeFormattedPHPToExcel1900(): array { return require 'tests/data/Shared/Date/FormattedPHPToExcel1900.php'; } @@ -139,7 +146,7 @@ class DateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDateTimeExcelToTimestamp1904() + public function providerDateTimeExcelToTimestamp1904(): array { return require 'tests/data/Shared/Date/ExcelToTimestamp1904.php'; } @@ -158,7 +165,7 @@ class DateTest extends TestCase self::assertEqualsWithDelta($expectedResult, $result, 1E-5); } - public function providerDateTimeTimestampToExcel1904() + public function providerDateTimeTimestampToExcel1904(): array { return require 'tests/data/Shared/Date/TimestampToExcel1904.php'; } @@ -174,7 +181,7 @@ class DateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerIsDateTimeFormatCode() + public function providerIsDateTimeFormatCode(): array { return require 'tests/data/Shared/Date/FormatCodes.php'; } @@ -197,7 +204,7 @@ class DateTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerDateTimeExcelToTimestamp1900Timezone() + public function providerDateTimeExcelToTimestamp1900Timezone(): array { return require 'tests/data/Shared/Date/ExcelToTimestamp1900Timezone.php'; } diff --git a/tests/PhpSpreadsheetTests/Shared/FontTest.php b/tests/PhpSpreadsheetTests/Shared/FontTest.php index bc917654..9bc1d18a 100644 --- a/tests/PhpSpreadsheetTests/Shared/FontTest.php +++ b/tests/PhpSpreadsheetTests/Shared/FontTest.php @@ -49,7 +49,7 @@ class FontTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerFontSizeToPixels() + public function providerFontSizeToPixels(): array { return require 'tests/data/Shared/FontSizeToPixels.php'; } @@ -66,7 +66,7 @@ class FontTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerInchSizeToPixels() + public function providerInchSizeToPixels(): array { return require 'tests/data/Shared/InchSizeToPixels.php'; } @@ -83,7 +83,7 @@ class FontTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerCentimeterSizeToPixels() + public function providerCentimeterSizeToPixels(): array { return require 'tests/data/Shared/CentimeterSizeToPixels.php'; } diff --git a/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php b/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php index 0d286725..e85b9fa3 100644 --- a/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php +++ b/tests/PhpSpreadsheetTests/Shared/PasswordHasherTest.php @@ -18,7 +18,7 @@ class PasswordHasherTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerHashPassword() + public function providerHashPassword(): array { return require 'tests/data/Shared/PasswordHashes.php'; } diff --git a/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php b/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php index 41ed0b21..92f197a2 100644 --- a/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php +++ b/tests/PhpSpreadsheetTests/Shared/StringHelperTest.php @@ -7,10 +7,19 @@ use PHPUnit\Framework\TestCase; class StringHelperTest extends TestCase { + /** + * @var string + */ private $currencyCode; + /** + * @var string + */ private $decimalSeparator; + /** + * @var string + */ private $thousandsSeparator; protected function setUp(): void diff --git a/tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php b/tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php index ff38badf..edad6e6b 100644 --- a/tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php +++ b/tests/PhpSpreadsheetTests/Shared/TimeZoneTest.php @@ -3,14 +3,21 @@ namespace PhpOffice\PhpSpreadsheetTests\Shared; use DateTime; +use DateTimeZone; use PhpOffice\PhpSpreadsheet\Shared\Date; use PhpOffice\PhpSpreadsheet\Shared\TimeZone; use PHPUnit\Framework\TestCase; class TimeZoneTest extends TestCase { + /** + * @var string + */ private $tztimezone; + /** + * @var null|DateTimeZone + */ private $dttimezone; protected function setUp(): void diff --git a/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php b/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php index 32fa9d31..a12a438c 100644 --- a/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php +++ b/tests/PhpSpreadsheetTests/Shared/Trend/ExponentialBestFitTest.php @@ -42,7 +42,7 @@ class ExponentialBestFitTest extends TestCase self::assertSame($expectedGoodnessOfFit[1], $bestFit->getGoodnessOfFit()); } - public function providerExponentialBestFit() + public function providerExponentialBestFit(): array { return require 'tests/data/Shared/Trend/ExponentialBestFit.php'; } diff --git a/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php b/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php index 02b82038..9ada87a5 100644 --- a/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php +++ b/tests/PhpSpreadsheetTests/Shared/Trend/LinearBestFitTest.php @@ -42,7 +42,7 @@ class LinearBestFitTest extends TestCase self::assertSame($expectedGoodnessOfFit[1], $bestFit->getGoodnessOfFit()); } - public function providerLinearBestFit() + public function providerLinearBestFit(): array { return require 'tests/data/Shared/Trend/LinearBestFit.php'; } diff --git a/tests/PhpSpreadsheetTests/SpreadsheetTest.php b/tests/PhpSpreadsheetTests/SpreadsheetTest.php index cf293001..7f159d67 100644 --- a/tests/PhpSpreadsheetTests/SpreadsheetTest.php +++ b/tests/PhpSpreadsheetTests/SpreadsheetTest.php @@ -26,10 +26,7 @@ class SpreadsheetTest extends TestCase $this->object->addSheet($sheet); } - /** - * @return array - */ - public function dataProviderForSheetNames() + public function dataProviderForSheetNames(): array { $array = [ [0, 'someSheet1'], diff --git a/tests/PhpSpreadsheetTests/Style/ColorTest.php b/tests/PhpSpreadsheetTests/Style/ColorTest.php index 2c017ff4..3a66192d 100644 --- a/tests/PhpSpreadsheetTests/Style/ColorTest.php +++ b/tests/PhpSpreadsheetTests/Style/ColorTest.php @@ -19,7 +19,7 @@ class ColorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerColorGetRed() + public function providerColorGetRed(): array { return require 'tests/data/Style/ColorGetRed.php'; } @@ -36,7 +36,7 @@ class ColorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerColorGetGreen() + public function providerColorGetGreen(): array { return require 'tests/data/Style/ColorGetGreen.php'; } @@ -53,7 +53,7 @@ class ColorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerColorGetBlue() + public function providerColorGetBlue(): array { return require 'tests/data/Style/ColorGetBlue.php'; } @@ -69,7 +69,7 @@ class ColorTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerColorChangeBrightness() + public function providerColorChangeBrightness(): array { return require 'tests/data/Style/ColorChangeBrightness.php'; } diff --git a/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php b/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php index 6bf7db04..e386b292 100644 --- a/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php +++ b/tests/PhpSpreadsheetTests/Style/NumberFormatTest.php @@ -8,10 +8,19 @@ use PHPUnit\Framework\TestCase; class NumberFormatTest extends TestCase { + /** + * @var string + */ private $currencyCode; + /** + * @var string + */ private $decimalSeparator; + /** + * @var string + */ private $thousandsSeparator; protected function setUp(): void @@ -41,7 +50,7 @@ class NumberFormatTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerNumberFormat() + public function providerNumberFormat(): array { return require 'tests/data/Style/NumberFormat.php'; } @@ -57,7 +66,7 @@ class NumberFormatTest extends TestCase self::assertEquals($expectedResult, $result); } - public function providerNumberFormatDates() + public function providerNumberFormatDates(): array { return require 'tests/data/Style/NumberFormatDates.php'; } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php index 156a95de..276836c9 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/Column/RuleTest.php @@ -3,12 +3,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; +use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class RuleTest extends TestCase { + /** + * @var Rule + */ private $testAutoFilterRuleObject; + /** + * @var Column&MockObject + */ private $mockAutoFilterColumnObject; protected function setUp(): void @@ -17,7 +25,7 @@ class RuleTest extends TestCase ->disableOriginalConstructor() ->getMock(); - $this->testAutoFilterRuleObject = new Column\Rule( + $this->testAutoFilterRuleObject = new Rule( $this->mockAutoFilterColumnObject ); } @@ -25,16 +33,16 @@ class RuleTest extends TestCase public function testGetRuleType(): void { $result = $this->testAutoFilterRuleObject->getRuleType(); - self::assertEquals(Column\Rule::AUTOFILTER_RULETYPE_FILTER, $result); + self::assertEquals(Rule::AUTOFILTER_RULETYPE_FILTER, $result); } public function testSetRuleType(): void { - $expectedResult = Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP; + $expectedResult = Rule::AUTOFILTER_RULETYPE_DATEGROUP; // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterRuleObject->setRuleType($expectedResult); - self::assertInstanceOf(Column\Rule::class, $result); + self::assertInstanceOf(Rule::class, $result); $result = $this->testAutoFilterRuleObject->getRuleType(); self::assertEquals($expectedResult, $result); @@ -46,7 +54,7 @@ class RuleTest extends TestCase // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterRuleObject->setValue($expectedResult); - self::assertInstanceOf(Column\Rule::class, $result); + self::assertInstanceOf(Rule::class, $result); $result = $this->testAutoFilterRuleObject->getValue(); self::assertEquals($expectedResult, $result); @@ -55,16 +63,16 @@ class RuleTest extends TestCase public function testGetOperator(): void { $result = $this->testAutoFilterRuleObject->getOperator(); - self::assertEquals(Column\Rule::AUTOFILTER_COLUMN_RULE_EQUAL, $result); + self::assertEquals(Rule::AUTOFILTER_COLUMN_RULE_EQUAL, $result); } public function testSetOperator(): void { - $expectedResult = Column\Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN; + $expectedResult = Rule::AUTOFILTER_COLUMN_RULE_LESSTHAN; // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterRuleObject->setOperator($expectedResult); - self::assertInstanceOf(Column\Rule::class, $result); + self::assertInstanceOf(Rule::class, $result); $result = $this->testAutoFilterRuleObject->getOperator(); self::assertEquals($expectedResult, $result); @@ -72,11 +80,11 @@ class RuleTest extends TestCase public function testSetGrouping(): void { - $expectedResult = Column\Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH; + $expectedResult = Rule::AUTOFILTER_RULETYPE_DATEGROUP_MONTH; // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterRuleObject->setGrouping($expectedResult); - self::assertInstanceOf(Column\Rule::class, $result); + self::assertInstanceOf(Rule::class, $result); $result = $this->testAutoFilterRuleObject->getGrouping(); self::assertEquals($expectedResult, $result); @@ -92,12 +100,12 @@ class RuleTest extends TestCase { // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterRuleObject->setParent($this->mockAutoFilterColumnObject); - self::assertInstanceOf(Column\Rule::class, $result); + self::assertInstanceOf(Rule::class, $result); } public function testClone(): void { $result = clone $this->testAutoFilterRuleObject; - self::assertInstanceOf(Column\Rule::class, $result); + self::assertInstanceOf(Rule::class, $result); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php index ef67b05d..93369626 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilter/ColumnTest.php @@ -3,14 +3,25 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet\AutoFilter; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter; +use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ColumnTest extends TestCase { + /** + * @var string + */ private $testInitialColumn = 'H'; + /** + * @var Column + */ private $testAutoFilterColumnObject; + /** + * @var AutoFilter&MockObject + */ private $mockAutoFilterObject; protected function setUp(): void @@ -23,7 +34,7 @@ class ColumnTest extends TestCase ->method('testColumnInRange') ->willReturn(3); - $this->testAutoFilterColumnObject = new AutoFilter\Column($this->testInitialColumn, $this->mockAutoFilterObject); + $this->testAutoFilterColumnObject = new Column($this->testInitialColumn, $this->mockAutoFilterObject); } public function testGetColumnIndex(): void @@ -38,7 +49,7 @@ class ColumnTest extends TestCase // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterColumnObject->setColumnIndex($expectedResult); - self::assertInstanceOf(AutoFilter\Column::class, $result); + self::assertInstanceOf(Column::class, $result); $result = $this->testAutoFilterColumnObject->getColumnIndex(); self::assertEquals($expectedResult, $result); @@ -54,22 +65,22 @@ class ColumnTest extends TestCase { // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterColumnObject->setParent($this->mockAutoFilterObject); - self::assertInstanceOf(AutoFilter\Column::class, $result); + self::assertInstanceOf(Column::class, $result); } public function testGetFilterType(): void { $result = $this->testAutoFilterColumnObject->getFilterType(); - self::assertEquals(AutoFilter\Column::AUTOFILTER_FILTERTYPE_FILTER, $result); + self::assertEquals(Column::AUTOFILTER_FILTERTYPE_FILTER, $result); } public function testSetFilterType(): void { - $result = $this->testAutoFilterColumnObject->setFilterType(AutoFilter\Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); - self::assertInstanceOf(AutoFilter\Column::class, $result); + $result = $this->testAutoFilterColumnObject->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER); + self::assertInstanceOf(Column::class, $result); $result = $this->testAutoFilterColumnObject->getFilterType(); - self::assertEquals(AutoFilter\Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER, $result); + self::assertEquals(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER, $result); } public function testSetInvalidFilterTypeThrowsException(): void @@ -84,16 +95,16 @@ class ColumnTest extends TestCase public function testGetJoin(): void { $result = $this->testAutoFilterColumnObject->getJoin(); - self::assertEquals(AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_OR, $result); + self::assertEquals(Column::AUTOFILTER_COLUMN_JOIN_OR, $result); } public function testSetJoin(): void { - $result = $this->testAutoFilterColumnObject->setJoin(AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_AND); - self::assertInstanceOf(AutoFilter\Column::class, $result); + $result = $this->testAutoFilterColumnObject->setJoin(Column::AUTOFILTER_COLUMN_JOIN_AND); + self::assertInstanceOf(Column::class, $result); $result = $this->testAutoFilterColumnObject->getJoin(); - self::assertEquals(AutoFilter\Column::AUTOFILTER_COLUMN_JOIN_AND, $result); + self::assertEquals(Column::AUTOFILTER_COLUMN_JOIN_AND, $result); } public function testSetInvalidJoinThrowsException(): void @@ -114,7 +125,7 @@ class ColumnTest extends TestCase // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterColumnObject->setAttributes($attributeSet); - self::assertInstanceOf(AutoFilter\Column::class, $result); + self::assertInstanceOf(Column::class, $result); } public function testGetAttributes(): void @@ -141,7 +152,7 @@ class ColumnTest extends TestCase foreach ($attributeSet as $attributeName => $attributeValue) { // Setters return the instance to implement the fluent interface $result = $this->testAutoFilterColumnObject->setAttribute($attributeName, $attributeValue); - self::assertInstanceOf(AutoFilter\Column::class, $result); + self::assertInstanceOf(Column::class, $result); } } @@ -166,7 +177,7 @@ class ColumnTest extends TestCase { $originalRule = $this->testAutoFilterColumnObject->createRule(); $result = clone $this->testAutoFilterColumnObject; - self::assertInstanceOf(AutoFilter\Column::class, $result); + self::assertInstanceOf(Column::class, $result); self::assertCount(1, $result->getRules()); self::assertContainsOnlyInstancesOf(AutoFilter\Column\Rule::class, $result->getRules()); $clonedRule = $result->getRules()[0]; diff --git a/tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php b/tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php index 17b4c022..7f218b54 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php @@ -6,10 +6,14 @@ use PhpOffice\PhpSpreadsheet\Collection\Cells; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter; use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class AutoFilterTest extends TestCase { + /** + * @var string + */ private $testInitialRange = 'H2:O256'; /** @@ -17,8 +21,14 @@ class AutoFilterTest extends TestCase */ private $testAutoFilterObject; + /** + * @var Worksheet&MockObject + */ private $mockWorksheetObject; + /** + * @var Cells&MockObject + */ private $cellCollection; protected function setUp(): void diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php index 1fa25330..9d5f4977 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnCellIteratorTest.php @@ -5,13 +5,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Worksheet\ColumnCellIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ColumnCellIteratorTest extends TestCase { - public $mockWorksheet; + /** + * @var Worksheet&MockObject + */ + private $mockWorksheet; - public $mockCell; + /** + * @var Cell&MockObject + */ + private $mockCell; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php index b10875c2..8062a24c 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php @@ -40,6 +40,6 @@ class ColumnDimensionTest extends TestCase $columnDimension = new ColumnDimension(); $columnDimension->setAutoSize($expected); $result = $columnDimension->getAutoSize(); - self::assertSame($expected, $result); + self::assertTrue($result); } } diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php index 71a05d48..98a402fe 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnIteratorTest.php @@ -5,20 +5,18 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Column; use PhpOffice\PhpSpreadsheet\Worksheet\ColumnIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ColumnIteratorTest extends TestCase { - public $mockWorksheet; - - public $mockColumn; + /** + * @var Worksheet&MockObject + */ + private $mockWorksheet; protected function setUp(): void { - $this->mockColumn = $this->getMockBuilder(Column::class) - ->disableOriginalConstructor() - ->getMock(); - $this->mockWorksheet = $this->getMockBuilder(Worksheet::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php index 0abff0ec..7795b5ae 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnTest.php @@ -5,13 +5,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Column; use PhpOffice\PhpSpreadsheet\Worksheet\ColumnCellIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class ColumnTest extends TestCase { - public $mockWorksheet; - - public $mockColumn; + /** + * @var Worksheet&MockObject + */ + private $mockWorksheet; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php b/tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php index 4105c91c..85191746 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/RowCellIteratorTest.php @@ -5,13 +5,20 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Worksheet\RowCellIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class RowCellIteratorTest extends TestCase { - public $mockWorksheet; + /** + * @var Worksheet&MockObject + */ + private $mockWorksheet; - public $mockCell; + /** + * @var Cell&MockObject + */ + private $mockCell; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php b/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php index c527f434..6228a320 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/RowIteratorTest.php @@ -5,20 +5,18 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Row; use PhpOffice\PhpSpreadsheet\Worksheet\RowIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class RowIteratorTest extends TestCase { - public $mockWorksheet; - - public $mockRow; + /** + * @var Worksheet&MockObject + */ + private $mockWorksheet; protected function setUp(): void { - $this->mockRow = $this->getMockBuilder(Row::class) - ->disableOriginalConstructor() - ->getMock(); - $this->mockWorksheet = $this->getMockBuilder(Worksheet::class) ->disableOriginalConstructor() ->getMock(); diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowTest.php b/tests/PhpSpreadsheetTests/Worksheet/RowTest.php index 93ff589c..9dea36aa 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/RowTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/RowTest.php @@ -5,13 +5,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Row; use PhpOffice\PhpSpreadsheet\Worksheet\RowCellIterator; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class RowTest extends TestCase { - public $mockWorksheet; - - public $mockRow; + /** + * @var Worksheet&MockObject + */ + private $mockWorksheet; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php index 62238b68..24775e3b 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php @@ -5,11 +5,15 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; use PhpOffice\PhpSpreadsheet\Exception; use PhpOffice\PhpSpreadsheet\Reader\Xlsx; use PhpOffice\PhpSpreadsheet\Settings; +use PhpOffice\PhpSpreadsheet\Spreadsheet; use PHPUnit\Framework\TestCase; class WorksheetNamedRangesTest extends TestCase { - protected $spreadsheet; + /** + * @var Spreadsheet + */ + private $spreadsheet; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php b/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php index 46c848ba..5377444d 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php @@ -18,7 +18,7 @@ class WorksheetTest extends TestCase self::assertSame($testTitle, $worksheet->getTitle()); } - public function setTitleInvalidProvider() + public function setTitleInvalidProvider(): array { return [ [str_repeat('a', 32), 'Maximum 31 characters allowed in sheet title.'], @@ -76,7 +76,7 @@ class WorksheetTest extends TestCase self::assertSame($testCodeName, $worksheet->getCodeName()); } - public function setCodeNameInvalidProvider() + public function setCodeNameInvalidProvider(): array { return [ [str_repeat('a', 32), 'Maximum 31 characters allowed in sheet code name.'], @@ -132,7 +132,7 @@ class WorksheetTest extends TestCase self::assertSame('B2', $worksheet->getTopLeftCell()); } - public function extractSheetTitleProvider() + public function extractSheetTitleProvider(): array { return [ ['B2', '', '', 'B2'], @@ -274,7 +274,7 @@ class WorksheetTest extends TestCase self::assertSame($expectedData, $worksheet->toArray()); } - public function removeRowsProvider() + public function removeRowsProvider(): array { return [ 'Remove all rows except first one' => [ diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php index d048183c..716a3dcc 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php @@ -33,7 +33,7 @@ class CsvEnclosureTest extends Functional\AbstractFunctional $writer = new CsvWriter($spreadsheet); $writer->setDelimiter($delimiter); $writer->setEnclosure($enclosure); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $filedata = file_get_contents($filename); $filedata = preg_replace('/\\r?\\n/', $delimiter, $filedata); @@ -64,7 +64,7 @@ class CsvEnclosureTest extends Functional\AbstractFunctional $writer->setDelimiter($delimiter); $writer->setEnclosure($enclosure); self::assertEquals('', $writer->getEnclosure()); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $filedata = file_get_contents($filename); $filedata = preg_replace('/\\r?\\n/', $delimiter, $filedata); @@ -95,7 +95,7 @@ class CsvEnclosureTest extends Functional\AbstractFunctional $writer = new CsvWriter($spreadsheet); self::assertTrue($writer->getEnclosureRequired()); $writer->setEnclosureRequired(false)->setDelimiter($delimiter)->setEnclosure($enclosure); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $filedata = file_get_contents($filename); $filedata = preg_replace('/\\r?\\n/', $delimiter, $filedata); @@ -149,7 +149,7 @@ class CsvEnclosureTest extends Functional\AbstractFunctional $writer = new CsvWriter($spreadsheet); self::assertTrue($writer->getEnclosureRequired()); $writer->setEnclosureRequired(false)->setDelimiter($delimiter)->setEnclosure($enclosure); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $filedata = file_get_contents($filename); $filedata = preg_replace('/\\r/', '', $filedata); @@ -176,7 +176,7 @@ class CsvEnclosureTest extends Functional\AbstractFunctional $sheet->setCellValue('C1', '4'); $writer = new CsvWriter($spreadsheet); $writer->setEnclosureRequired(false)->setDelimiter($delimiter)->setEnclosure($enclosure); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $reader = new CsvReader(); $reader->setDelimiter($delimiter); @@ -200,7 +200,7 @@ class CsvEnclosureTest extends Functional\AbstractFunctional $sheet->setCellValue('C1', '4'); $writer = new CsvWriter($spreadsheet); $writer->setDelimiter($delimiter)->setEnclosure($enclosure); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $reader = new CsvReader(); $reader->setDelimiter($delimiter); diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php index 510515c3..81e4428e 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvOutputEncodingTest.php @@ -18,7 +18,7 @@ class CsvOutputEncodingTest extends Functional\AbstractFunctional $writer = new CsvWriter($spreadsheet); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test-SJIS-win'); + $filename = File::temporaryFilename(); $writer->setUseBOM(false); $writer->setOutputEncoding('SJIS-win'); $writer->save($filename); diff --git a/tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php b/tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php index 7fe1902b..aa9a8fc3 100644 --- a/tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php @@ -23,7 +23,7 @@ class CsvWriteTest extends Functional\AbstractFunctional $writer = new CsvWriter($spreadsheet); $writer->setSheetIndex(1); self::assertEquals(1, $writer->getSheetIndex()); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $reader = new CsvReader(); $newspreadsheet = $reader->load($filename); diff --git a/tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php b/tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php index 94c201a7..ae71ca55 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/CallbackTest.php @@ -42,7 +42,7 @@ EOF; self::assertEquals($html3, $html1); $writer->setEditHtmlCallback([$this, 'yellowBody']); - $oufil = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $oufil = File::temporaryFilename(); $writer->save($oufil); $html4 = file_get_contents($oufil); unlink($oufil); diff --git a/tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php b/tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php index 0d43d7eb..a4f474fa 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php @@ -8,9 +8,12 @@ use PhpOffice\PhpSpreadsheetTests\Functional; class HtmlCommentsTest extends Functional\AbstractFunctional { + /** + * @var Spreadsheet + */ private $spreadsheet; - public function providerCommentRichText() + public function providerCommentRichText(): array { $valueSingle = 'I am comment.'; $valueMulti = 'I am ' . PHP_EOL . 'multi-line' . PHP_EOL . 'comment.'; diff --git a/tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php b/tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php index 340e820b..199ab529 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php @@ -10,10 +10,19 @@ use PhpOffice\PhpSpreadsheetTests\Functional; class HtmlNumberFormatTest extends Functional\AbstractFunctional { + /** + * @var string + */ private $currency; + /** + * @var string + */ private $decsep; + /** + * @var string + */ private $thosep; protected function setUp(): void @@ -172,7 +181,7 @@ class HtmlNumberFormatTest extends Functional\AbstractFunctional $this->writeAndReload($spreadsheet, 'Html'); } - public function providerNumberFormat() + public function providerNumberFormat(): array { return require __DIR__ . '/../../../data/Style/NumberFormat.php'; } @@ -208,7 +217,7 @@ class HtmlNumberFormatTest extends Functional\AbstractFunctional $this->writeAndReload($spreadsheet, 'Html'); } - public function providerNumberFormatDates() + public function providerNumberFormatDates(): array { return require __DIR__ . '/../../../data/Style/NumberFormatDates.php'; } diff --git a/tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php b/tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php index 6cc7f18f..40099177 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php @@ -9,6 +9,9 @@ use PhpOffice\PhpSpreadsheetTests\Functional; class ImagesRootTest extends Functional\AbstractFunctional { + /** + * @var false|string + */ private $curdir; protected function setUp(): void diff --git a/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php b/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php index de0ac54d..4d8b03a5 100644 --- a/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php @@ -10,7 +10,7 @@ use PhpOffice\PhpSpreadsheetTests\Functional; class XssVulnerabilityTest extends Functional\AbstractFunctional { - public function providerAcceptableMarkupRichText() + public function providerAcceptableMarkupRichText(): array { return [ 'basic text' => ['Hello, I am safely viewing your site', 'Hello, I am safely viewing your site'], @@ -37,7 +37,7 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional ->getComment('A1') ->setText($richText); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer = IOFactory::createWriter($spreadsheet, 'Html'); $writer->save($filename); @@ -48,7 +48,7 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional self::assertStringContainsString($adjustedTextString, $verify); } - public function providerXssRichText() + public function providerXssRichText(): array { return [ 'script tag' => ["Hello, I am trying to your site"], @@ -77,7 +77,7 @@ class XssVulnerabilityTest extends Functional\AbstractFunctional ->getComment('A1') ->setText($richText); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer = IOFactory::createWriter($spreadsheet, 'Html'); $writer->save($filename); diff --git a/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php b/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php index 2ebd4984..917a0410 100644 --- a/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Ods/ContentTest.php @@ -16,8 +16,15 @@ use PHPUnit\Framework\TestCase; class ContentTest extends TestCase { + /** + * @var string + */ private $samplesPath = 'tests/data/Writer/Ods'; + /** + * @var string + */ + /** * @var string */ diff --git a/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php b/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php index c1a57eb5..59f480fd 100644 --- a/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/RetainSelectedCellsTest.php @@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; class RetainSelectedCellsTest extends AbstractFunctional { - public function providerFormats() + public function providerFormats(): array { return [ ['Xls'], diff --git a/tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php b/tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php index bbb00d89..3965db62 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php @@ -19,7 +19,7 @@ class FormulaErrTest extends TestCase $sheet0->setCellValue('C1', '=DEFNAM=2'); $sheet0->setCellValue('D1', '=CONCAT("X",DEFNAM)'); $writer = IOFactory::createWriter($obj, 'Xls'); - $filename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $filename = File::temporaryFilename(); $writer->save($filename); $reader = IOFactory::createReader('Xls'); $robj = $reader->load($filename); diff --git a/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php b/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php index 5ebe645f..160a665a 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php @@ -47,7 +47,7 @@ class WorkbookTest extends TestCase self::assertEquals($expectedResult, $palette); } - public function providerAddColor() + public function providerAddColor(): array { $this->setUp(); diff --git a/tests/PhpSpreadsheetTests/Writer/Xls/XlsGifBmpTest.php b/tests/PhpSpreadsheetTests/Writer/Xls/XlsGifBmpTest.php index ceba7e54..03f201be 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xls/XlsGifBmpTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xls/XlsGifBmpTest.php @@ -9,6 +9,9 @@ use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional; class XlsGifBmpTest extends AbstractFunctional { + /** + * @var string + */ private $filename = ''; protected function tearDown(): void diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php index ef2002b5..88c63306 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php @@ -13,7 +13,7 @@ class DrawingsTest extends AbstractFunctional /** * @var int */ - protected $prevValue; + private $prevValue; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php index 746b9846..22f3284b 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php @@ -18,7 +18,7 @@ class FloatsRetainedTest extends TestCase */ public function testIntyFloatsRetainedByWriter($value): void { - $outputFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outputFilename = File::temporaryFilename(); Settings::setLibXmlLoaderOptions(null); $sheet = new Spreadsheet(); $sheet->getActiveSheet()->getCell('A1')->setValue($value); @@ -33,7 +33,7 @@ class FloatsRetainedTest extends TestCase self::assertSame($value, $sheet->getActiveSheet()->getCell('A1')->getValue()); } - public function providerIntyFloatsRetainedByWriter() + public function providerIntyFloatsRetainedByWriter(): array { return [ [-1.0], diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php index 373ef37f..3a9fb1cc 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php @@ -6,9 +6,15 @@ use PHPUnit\Framework\TestCase; class LocaleFloatsTest extends TestCase { - protected $localeAdjusted; + /** + * @var bool + */ + private $localeAdjusted; - protected $currentLocale; + /** + * @var false|string + */ + private $currentLocale; protected function setUp(): void { diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php index d4fe5b22..826c482d 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php @@ -15,7 +15,7 @@ class StartsWithHashTest extends TestCase { public function testStartWithHash(): void { - $outputFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outputFilename = File::temporaryFilename(); Settings::setLibXmlLoaderOptions(null); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); @@ -40,7 +40,7 @@ class StartsWithHashTest extends TestCase public function testStartWithHashReadRaw(): void { // Make sure raw data indicates A3 is an error, but A2 isn't. - $outputFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $outputFilename = File::temporaryFilename(); Settings::setLibXmlLoaderOptions(null); $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php index 660e40fe..def6f70e 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php @@ -15,7 +15,7 @@ class UnparsedDataCloneTest extends TestCase public function testLoadSaveXlsxWithUnparsedDataClone(): void { $sampleFilename = 'tests/data/Writer/XLSX/drawing_on_2nd_page.xlsx'; - $resultFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $resultFilename = File::temporaryFilename(); Settings::setLibXmlLoaderOptions(null); // reset to default options $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $spreadsheet = $reader->load($sampleFilename); @@ -60,8 +60,8 @@ class UnparsedDataCloneTest extends TestCase public function testSaveTwice(): void { $sampleFilename = 'tests/data/Writer/XLSX/drawing_on_2nd_page.xlsx'; - $resultFilename1 = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test1'); - $resultFilename2 = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test2'); + $resultFilename1 = File::temporaryFilename(); + $resultFilename2 = File::temporaryFilename(); self::assertNotEquals($resultFilename1, $resultFilename2); Settings::setLibXmlLoaderOptions(null); // reset to default options $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php index 4ea6f955..a2f21aef 100644 --- a/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataTest.php @@ -16,7 +16,7 @@ class UnparsedDataTest extends TestCase public function testLoadSaveXlsxWithUnparsedData(): void { $sampleFilename = 'tests/data/Writer/XLSX/form_pass_print.xlsm'; - $resultFilename = tempnam(File::sysGetTempDir(), 'phpspreadsheet-test'); + $resultFilename = File::temporaryFilename(); Settings::setLibXmlLoaderOptions(null); // reset to default options $reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx(); $excel = $reader->load($sampleFilename); diff --git a/tests/data/Calculation/Calculation.php b/tests/data/Calculation/Calculation.php index 2f9e0a0c..e49bed9f 100644 --- a/tests/data/Calculation/Calculation.php +++ b/tests/data/Calculation/Calculation.php @@ -1,6 +1,6 @@ 0, 2 > 0, + true, true, ], [ true, @@ -15,23 +15,23 @@ return [ ], [ true, - 1 > 0, 0 > 1, + true, false, ], [ true, - 0 > 1, 2 > 0, + false, true, ], [ false, - 0 > 1, 0 > 2, + false, false, ], [ false, - 1 > 0, 2 > 0, 0 > 1, 0 > 2, + true, true, false, false, ], [ true, - 1 > 0, 2 > 0, 3 > 0, 0 > 1, + true, true, true, false, ], [ false, From a34695e0f9e7125e701b255f17f1436c2554eabe Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Mon, 12 Apr 2021 22:08:58 +0200 Subject: [PATCH 180/187] Financial functions more rationalization (#1990) * Additional unit tests and rationalisation for Financial Functions * Providing a series of sample files for Financial functions * Refactor the last of the existing Financial functions * Some more unit tests with default assignments from null arguments Co-authored-by: Adrien Crivelli --- phpstan-baseline.neon | 908 +----------------- samples/Calculations/Financial/ACCRINT.php | 35 + samples/Calculations/Financial/ACCRINTM.php | 33 + samples/Calculations/Financial/AMORDEGRC.php | 38 + samples/Calculations/Financial/AMORLINC.php | 38 + samples/Calculations/Financial/COUPDAYBS.php | 29 + samples/Calculations/Financial/COUPDAYS.php | 29 + samples/Calculations/Financial/COUPDAYSNC.php | 29 + samples/Calculations/Financial/COUPNCD.php | 30 + samples/Calculations/Financial/COUPNUM.php | 30 + samples/Calculations/Financial/COUPPCD.php | 30 + samples/Calculations/Financial/CUMIPMT.php | 38 + samples/Calculations/Financial/CUMPRINC.php | 38 + samples/Calculations/Financial/DB.php | 50 + samples/Calculations/Financial/DDB.php | 36 + samples/Calculations/Financial/DISC.php | 32 + samples/Calculations/Financial/DOLLARDE.php | 30 + samples/Calculations/Financial/DOLLARFR.php | 30 + samples/Calculations/Financial/EFFECT.php | 31 + samples/Calculations/Financial/FV.php | 36 + samples/Calculations/Financial/FVSCHEDULE.php | 36 + samples/Calculations/Financial/INTRATE.php | 32 + samples/Calculations/Financial/IPMT.php | 37 + samples/Calculations/Financial/IRR.php | 38 + samples/Calculations/Financial/ISPMT.php | 36 + samples/Calculations/Financial/MIRR.php | 42 + samples/Calculations/Financial/NOMINAL.php | 31 + samples/Calculations/Financial/NPER.php | 39 + samples/Calculations/Financial/NPV.php | 43 + .../Calculation/Calculation.php | 6 +- .../Calculation/DateTimeExcel/Helpers.php | 4 +- src/PhpSpreadsheet/Calculation/Financial.php | 167 ++-- .../Calculation/Financial/Amortization.php | 68 +- .../Calculation/Financial/BaseValidations.php | 72 -- .../CashFlow/CashFlowValidations.php | 56 ++ .../Financial/CashFlow/Constant/Periodic.php | 81 +- .../CashFlow/Constant/Periodic/Cumulative.php | 60 +- .../CashFlow/Constant/Periodic/Interest.php | 70 +- .../Periodic/InterestAndPrincipal.php | 6 +- .../CashFlow/Constant/Periodic/Payments.php | 50 +- .../Calculation/Financial/CashFlow/Single.php | 27 +- .../Calculation/Financial/Constants.php | 19 + .../Calculation/Financial/Coupons.php | 139 +-- .../Calculation/Financial/Depreciation.php | 19 +- ...lidations.php => FinancialValidations.php} | 187 ++-- .../Calculation/Financial/Helpers.php | 31 +- .../Calculation/Financial/InterestRate.php | 10 +- .../Financial/Securities/AccruedInterest.php | 64 +- .../Financial/Securities/Constants.php | 13 - .../Financial/Securities/Price.php | 146 ++- .../Financial/Securities/Rates.php | 137 +++ .../Securities/SecurityValidations.php | 42 + .../Financial/Securities/Yields.php | 91 +- .../Calculation/Financial/TreasuryBill.php | 106 +- tests/data/Calculation/Financial/ACCRINT.php | 14 +- tests/data/Calculation/Financial/ACCRINTM.php | 4 + .../data/Calculation/Financial/AMORDEGRC.php | 28 + tests/data/Calculation/Financial/AMORLINC.php | 36 + .../data/Calculation/Financial/COUPDAYBS.php | 7 + tests/data/Calculation/Financial/COUPDAYS.php | 7 + .../data/Calculation/Financial/COUPDAYSNC.php | 7 + tests/data/Calculation/Financial/COUPNCD.php | 7 + tests/data/Calculation/Financial/COUPNUM.php | 7 + tests/data/Calculation/Financial/COUPPCD.php | 7 + tests/data/Calculation/Financial/CUMIPMT.php | 9 + tests/data/Calculation/Financial/CUMPRINC.php | 9 + tests/data/Calculation/Financial/DISC.php | 8 + .../Calculation/Financial/DaysPerYear.php | 14 +- tests/data/Calculation/Financial/FV.php | 18 +- tests/data/Calculation/Financial/INTRATE.php | 12 +- .../data/Calculation/Financial/PDURATION.php | 4 + tests/data/Calculation/Financial/PRICE.php | 10 + .../data/Calculation/Financial/PRICEDISC.php | 4 + tests/data/Calculation/Financial/PRICEMAT.php | 4 + tests/data/Calculation/Financial/RECEIVED.php | 28 + .../data/Calculation/Financial/YIELDDISC.php | 8 + tests/data/Calculation/Financial/YIELDMAT.php | 4 + tests/data/Calculation/Statistical/ZTEST.php | 10 + 78 files changed, 2242 insertions(+), 1579 deletions(-) create mode 100644 samples/Calculations/Financial/ACCRINT.php create mode 100644 samples/Calculations/Financial/ACCRINTM.php create mode 100644 samples/Calculations/Financial/AMORDEGRC.php create mode 100644 samples/Calculations/Financial/AMORLINC.php create mode 100644 samples/Calculations/Financial/COUPDAYBS.php create mode 100644 samples/Calculations/Financial/COUPDAYS.php create mode 100644 samples/Calculations/Financial/COUPDAYSNC.php create mode 100644 samples/Calculations/Financial/COUPNCD.php create mode 100644 samples/Calculations/Financial/COUPNUM.php create mode 100644 samples/Calculations/Financial/COUPPCD.php create mode 100644 samples/Calculations/Financial/CUMIPMT.php create mode 100644 samples/Calculations/Financial/CUMPRINC.php create mode 100644 samples/Calculations/Financial/DB.php create mode 100644 samples/Calculations/Financial/DDB.php create mode 100644 samples/Calculations/Financial/DISC.php create mode 100644 samples/Calculations/Financial/DOLLARDE.php create mode 100644 samples/Calculations/Financial/DOLLARFR.php create mode 100644 samples/Calculations/Financial/EFFECT.php create mode 100644 samples/Calculations/Financial/FV.php create mode 100644 samples/Calculations/Financial/FVSCHEDULE.php create mode 100644 samples/Calculations/Financial/INTRATE.php create mode 100644 samples/Calculations/Financial/IPMT.php create mode 100644 samples/Calculations/Financial/IRR.php create mode 100644 samples/Calculations/Financial/ISPMT.php create mode 100644 samples/Calculations/Financial/MIRR.php create mode 100644 samples/Calculations/Financial/NOMINAL.php create mode 100644 samples/Calculations/Financial/NPER.php create mode 100644 samples/Calculations/Financial/NPV.php delete mode 100644 src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/CashFlow/CashFlowValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Constants.php rename src/PhpSpreadsheet/Calculation/Financial/{Securities/BaseValidations.php => FinancialValidations.php} (51%) delete mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/Rates.php create mode 100644 src/PhpSpreadsheet/Calculation/Financial/Securities/SecurityValidations.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 494b90a8..4566305f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -700,236 +700,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Financial.php - - - message: "#^Result of && is always true\\.$#" - count: 2 - path: src/PhpSpreadsheet/Calculation/Financial.php - - - - message: "#^Unreachable statement \\- code above always terminates\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Amortization\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Amortization.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Cumulative\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Interest\\:\\:schedulePayment\\(\\) has no return typehint specified\\.$#" count: 1 @@ -970,411 +740,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\Payments\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Single\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Binary operation \"\\*\" between float\\|string and int results in an error\\.$#" - count: 2 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Binary operation \"\\*\" between float\\|string and int\\|string results in an error\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$next with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSalvage\\(\\) has parameter \\$salvage with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateLife\\(\\) has parameter \\$life with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validatePeriod\\(\\) has parameter \\$period with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMonth\\(\\) has parameter \\$month with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFactor\\(\\) has parameter \\$factor with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\InterestRate\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/InterestRate.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\TreasuryBill\\:\\:price\\(\\) should return float\\|string but returns float\\|int\\<0, max\\>\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\CashFlow\\\\Constant\\\\Periodic\\\\InterestAndPrincipal\\:\\:\\$interest has no typehint specified\\.$#" count: 1 @@ -1501,289 +866,74 @@ parameters: path: src/PhpSpreadsheet/Calculation/Financial/CashFlow/Variable/Periodic.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + message: "#^Binary operation \"\\*\" between float\\|string and int results in an error\\.$#" + count: 2 + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" + message: "#^Binary operation \"\\*\" between float\\|string and int\\|string results in an error\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has no return typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$next with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:couponFirstPeriodDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateIssueDate\\(\\) has no return typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Coupons\\:\\:validateCouponPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Coupons.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateIssueDate\\(\\) has parameter \\$issue with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateCost\\(\\) has parameter \\$cost with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSecurityPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateSalvage\\(\\) has parameter \\$salvage with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateSecurityPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateLife\\(\\) has parameter \\$life with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateRate\\(\\) has parameter \\$rate with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validatePeriod\\(\\) has parameter \\$period with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateParValue\\(\\) has parameter \\$parValue with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateMonth\\(\\) has parameter \\$month with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validatePrice\\(\\) has parameter \\$price with no typehint specified\\.$#" + message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Depreciation\\:\\:validateFactor\\(\\) has parameter \\$factor with no typehint specified\\.$#" count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateYield\\(\\) has parameter \\$yield with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateRedemption\\(\\) has parameter \\$redemption with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateDiscount\\(\\) has parameter \\$discount with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\AccruedInterest\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateIssueDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateIssueDate\\(\\) has parameter \\$issue with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSecurityPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateSecurityPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateRate\\(\\) has parameter \\$rate with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateParValue\\(\\) has parameter \\$parValue with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validatePrice\\(\\) has parameter \\$price with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateYield\\(\\) has parameter \\$yield with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateRedemption\\(\\) has parameter \\$redemption with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateDiscount\\(\\) has parameter \\$discount with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Price\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Price.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateDate\\(\\) has parameter \\$date with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSettlementDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSettlementDate\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateMaturityDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateMaturityDate\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateIssueDate\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateIssueDate\\(\\) has parameter \\$issue with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSecurityPeriod\\(\\) has parameter \\$maturity with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateSecurityPeriod\\(\\) has parameter \\$settlement with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateRate\\(\\) has parameter \\$rate with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateParValue\\(\\) has parameter \\$parValue with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validatePrice\\(\\) has parameter \\$price with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateYield\\(\\) has parameter \\$yield with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateRedemption\\(\\) has parameter \\$redemption with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateDiscount\\(\\) has parameter \\$discount with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateFrequency\\(\\) has parameter \\$frequency with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Financial\\\\Securities\\\\Yields\\:\\:validateBasis\\(\\) has parameter \\$basis with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php + path: src/PhpSpreadsheet/Calculation/Financial/Depreciation.php - message: "#^Strict comparison using \\=\\=\\= between string and null will always evaluate to false\\.$#" diff --git a/samples/Calculations/Financial/ACCRINT.php b/samples/Calculations/Financial/ACCRINT.php new file mode 100644 index 00000000..6f24f651 --- /dev/null +++ b/samples/Calculations/Financial/ACCRINT.php @@ -0,0 +1,35 @@ +log('Returns the accrued interest for a security that pays periodic interest.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Issue Date', DateHelper::getDateValue('01-Jan-2012')], + ['First Interest Date', DateHelper::getDateValue('01-Apr-2012')], + ['Settlement Date', DateHelper::getDateValue('31-Dec-2013')], + ['Annual Coupon Rate', 0.08], + ['Par Value', 10000], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B3')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); +$worksheet->getStyle('B4')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B5')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('B10', '=ACCRINT(B1, B2, B3, B4, B5, B6)'); +$worksheet->getStyle('B10')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B10')->getValue()); +$helper->log('ACCRINT() Result is ' . $worksheet->getCell('B10')->getFormattedValue()); diff --git a/samples/Calculations/Financial/ACCRINTM.php b/samples/Calculations/Financial/ACCRINTM.php new file mode 100644 index 00000000..8cc73899 --- /dev/null +++ b/samples/Calculations/Financial/ACCRINTM.php @@ -0,0 +1,33 @@ +log('Returns the accrued interest for a security that pays interest at maturity.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Issue Date', DateHelper::getDateValue('01-Jan-2012')], + ['Settlement Date', DateHelper::getDateValue('31-Dec-2012')], + ['Annual Coupon Rate', 0.08], + ['Par Value', 10000], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); +$worksheet->getStyle('B3')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B4')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('B6', '=ACCRINTM(B1, B2, B3, B4)'); +$worksheet->getStyle('B6')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('ACCRINTM() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/AMORDEGRC.php b/samples/Calculations/Financial/AMORDEGRC.php new file mode 100644 index 00000000..c9e0c4c9 --- /dev/null +++ b/samples/Calculations/Financial/AMORDEGRC.php @@ -0,0 +1,38 @@ +log('Returns the prorated linear depreciation of an asset for a specified accounting period.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Cost', 150.00], + ['Date Purchased', DateHelper::getDateValue('01-Jan-2015')], + ['First Period Date', DateHelper::getDateValue('30-Sep-2015')], + ['Salvage Value', 20.00], + ['Number of Periods', 1], + ['Depreciation Rate', 0.20], + ['Basis', FinancialConstants::BASIS_DAYS_PER_YEAR_360_EUROPEAN], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('$#,##0.00'); +$worksheet->getStyle('B2:B3')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); +$worksheet->getStyle('B4')->getNumberFormat()->setFormatCode('$#,##0.00'); +$worksheet->getStyle('B6')->getNumberFormat()->setFormatCode('0.00%'); + +// Now the formula +$worksheet->setCellValue('B10', '=AMORDEGRC(B1, B2, B3, B4, B5, B6, B7)'); +$worksheet->getStyle('B10')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B10')->getValue()); +$helper->log('AMORDEGRC() Result is ' . $worksheet->getCell('B10')->getFormattedValue()); diff --git a/samples/Calculations/Financial/AMORLINC.php b/samples/Calculations/Financial/AMORLINC.php new file mode 100644 index 00000000..3491eae0 --- /dev/null +++ b/samples/Calculations/Financial/AMORLINC.php @@ -0,0 +1,38 @@ +log('Returns the prorated linear depreciation of an asset for a specified accounting period.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Cost', 150.00], + ['Date Purchased', DateHelper::getDateValue('01-Jan-2015')], + ['First Period Date', DateHelper::getDateValue('30-Sep-2015')], + ['Salvage Value', 20.00], + ['Period', 1], + ['Depreciation Rate', 0.20], + ['Basis', FinancialConstants::BASIS_DAYS_PER_YEAR_360_EUROPEAN], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('$#,##0.00'); +$worksheet->getStyle('B2:B3')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); +$worksheet->getStyle('B4')->getNumberFormat()->setFormatCode('$#,##0.00'); +$worksheet->getStyle('B6')->getNumberFormat()->setFormatCode('0.00%'); + +// Now the formula +$worksheet->setCellValue('B10', '=AMORLINC(B1, B2, B3, B4, B5, B6, B7)'); +$worksheet->getStyle('B10')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B10')->getValue()); +$helper->log('AMORLINC() Result is ' . $worksheet->getCell('B10')->getFormattedValue()); diff --git a/samples/Calculations/Financial/COUPDAYBS.php b/samples/Calculations/Financial/COUPDAYBS.php new file mode 100644 index 00000000..727d17d9 --- /dev/null +++ b/samples/Calculations/Financial/COUPDAYBS.php @@ -0,0 +1,29 @@ +log('Returns the number of days from the beginning of a coupon\'s period to the settlement date.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Jan-2011')], + ['Maturity Date', DateHelper::getDateValue('25-Oct-2012')], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +// Now the formula +$worksheet->setCellValue('B6', '=COUPDAYBS(B1, B2, B3)'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('COUPDAYBS() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/COUPDAYS.php b/samples/Calculations/Financial/COUPDAYS.php new file mode 100644 index 00000000..f6e148cc --- /dev/null +++ b/samples/Calculations/Financial/COUPDAYS.php @@ -0,0 +1,29 @@ +log('Returns the number of days in the coupon period that contains the settlement date.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Jan-2011')], + ['Maturity Date', DateHelper::getDateValue('25-Oct-2012')], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +// Now the formula +$worksheet->setCellValue('B6', '=COUPDAYS(B1, B2, B3)'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('COUPDAYS() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/COUPDAYSNC.php b/samples/Calculations/Financial/COUPDAYSNC.php new file mode 100644 index 00000000..dfb21dd7 --- /dev/null +++ b/samples/Calculations/Financial/COUPDAYSNC.php @@ -0,0 +1,29 @@ +log('Returns the number of days from the settlement date to the next coupon date.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Jan-2011')], + ['Maturity Date', DateHelper::getDateValue('25-Oct-2012')], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +// Now the formula +$worksheet->setCellValue('B6', '=COUPDAYSNC(B1, B2, B3)'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('COUPDAYSNC() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/COUPNCD.php b/samples/Calculations/Financial/COUPNCD.php new file mode 100644 index 00000000..b38faf03 --- /dev/null +++ b/samples/Calculations/Financial/COUPNCD.php @@ -0,0 +1,30 @@ +log('Returns the next coupon date, after the settlement date.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Jan-2011')], + ['Maturity Date', DateHelper::getDateValue('25-Oct-2012')], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +// Now the formula +$worksheet->setCellValue('B6', '=COUPNCD(B1, B2, B3)'); +$worksheet->getStyle('B6')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('COUPNCD() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/COUPNUM.php b/samples/Calculations/Financial/COUPNUM.php new file mode 100644 index 00000000..b1bd0d52 --- /dev/null +++ b/samples/Calculations/Financial/COUPNUM.php @@ -0,0 +1,30 @@ +log('Returns the number of coupons payable, between a security\'s settlement date and maturity date,'); +$helper->log('rounded up to the nearest whole coupon.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Jan-2011')], + ['Maturity Date', DateHelper::getDateValue('25-Oct-2012')], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +// Now the formula +$worksheet->setCellValue('B6', '=COUPNUM(B1, B2, B3)'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('COUPNUM() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/COUPPCD.php b/samples/Calculations/Financial/COUPPCD.php new file mode 100644 index 00000000..8ac78606 --- /dev/null +++ b/samples/Calculations/Financial/COUPPCD.php @@ -0,0 +1,30 @@ +log('Returns the previous coupon date, before the settlement date for a security.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Jan-2011')], + ['Maturity Date', DateHelper::getDateValue('25-Oct-2012')], + ['Frequency', 4], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +// Now the formula +$worksheet->setCellValue('B6', '=COUPPCD(B1, B2, B3)'); +$worksheet->getStyle('B6')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); + +$helper->log($worksheet->getCell('B6')->getValue()); +$helper->log('COUPPCD() Result is ' . $worksheet->getCell('B6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/CUMIPMT.php b/samples/Calculations/Financial/CUMIPMT.php new file mode 100644 index 00000000..f97caec8 --- /dev/null +++ b/samples/Calculations/Financial/CUMIPMT.php @@ -0,0 +1,38 @@ +log('Returns the cumulative interest paid on a loan or investment, between two specified periods.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Interest Rate (per period)', 0.05 / 12], + ['Number of Periods', 5 * 12], + ['Present Value', 50000], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B3')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$baseRow = 5; +for ($year = 1; $year <= 5; ++$year) { + $row = (string) ($baseRow + $year); + $yearStartPeriod = (int) $year * 12 - 11; + $yearEndPeriod = (int) $year * 12; + + $worksheet->setCellValue("A{$row}", "Yr {$year}"); + $worksheet->setCellValue("B{$row}", "=CUMIPMT(\$B\$1, \$B\$2, \$B\$3, {$yearStartPeriod}, {$yearEndPeriod}, 0)"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("CUMIPMT() Year {$year} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/CUMPRINC.php b/samples/Calculations/Financial/CUMPRINC.php new file mode 100644 index 00000000..86de3070 --- /dev/null +++ b/samples/Calculations/Financial/CUMPRINC.php @@ -0,0 +1,38 @@ +log('Returns the cumulative payment on the principal of a loan or investment, between two specified periods.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Interest Rate (per period)', 0.05 / 12], + ['Number of Periods', 5 * 12], + ['Present Value', 50000], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B3')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$baseRow = 5; +for ($year = 1; $year <= 5; ++$year) { + $row = (string) ($baseRow + $year); + $yearStartPeriod = (int) $year * 12 - 11; + $yearEndPeriod = (int) $year * 12; + + $worksheet->setCellValue("A{$row}", "Yr {$year}"); + $worksheet->setCellValue("B{$row}", "=CUMPRINC(\$B\$1, \$B\$2, \$B\$3, {$yearStartPeriod}, {$yearEndPeriod}, 0)"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("CUMPRINC() Year {$year} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/DB.php b/samples/Calculations/Financial/DB.php new file mode 100644 index 00000000..0759c0aa --- /dev/null +++ b/samples/Calculations/Financial/DB.php @@ -0,0 +1,50 @@ +log('Returns the depreciation of an asset, using the Fixed Declining Balance Method,'); +$helper->log('for each period of the asset\'s lifetime.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Cost Value', 10000], + ['Salvage', 1000], + ['Life', 5, 'Years'], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$baseRow = 5; +for ($year = 1; $year <= 5; ++$year) { + $row = (string) ($baseRow + $year); + + $worksheet->setCellValue("A{$row}", "Depreciation after Yr {$year}"); + $worksheet->setCellValue("B{$row}", "=DB(\$B\$1, \$B\$2, \$B\$3, {$year})"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("DB() Year {$year} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} + +$helper->log('And with depreciation only starting after 6 months.'); + +$baseRow = 12; +for ($year = 1; $year <= 6; ++$year) { + $row = (string) ($baseRow + $year); + + $worksheet->setCellValue("A{$row}", "Depreciation after Yr {$year}"); + $worksheet->setCellValue("B{$row}", "=DB(\$B\$1, \$B\$2, \$B\$3, {$year}, 6)"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("DB() Year {$year} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/DDB.php b/samples/Calculations/Financial/DDB.php new file mode 100644 index 00000000..d261d4bd --- /dev/null +++ b/samples/Calculations/Financial/DDB.php @@ -0,0 +1,36 @@ +log('Returns the depreciation of an asset, using the Double Declining Balance Method,'); +$helper->log('for each period of the asset\'s lifetime.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Cost Value', 10000], + ['Salvage', 1000], + ['Life', 5, 'Years'], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$baseRow = 5; +for ($year = 1; $year <= 5; ++$year) { + $row = (string) ($baseRow + $year); + + $worksheet->setCellValue("A{$row}", "Depreciation after Yr {$year}"); + $worksheet->setCellValue("B{$row}", "=DDB(\$B\$1, \$B\$2, \$B\$3, {$year})"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("DDB() Year {$year} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/DISC.php b/samples/Calculations/Financial/DISC.php new file mode 100644 index 00000000..389d75e0 --- /dev/null +++ b/samples/Calculations/Financial/DISC.php @@ -0,0 +1,32 @@ +log('Returns the the Discount Rate for a security.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Apr-2016')], + ['Maturity Date', DateHelper::getDateValue('31-Mar-2021')], + ['Par Value', 95.00], + ['Redemption Value', 100.00], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); +$worksheet->getStyle('B3:B4')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('B7', '=DISC(B1, B2, B3, B4)'); +$worksheet->getStyle('B7')->getNumberFormat()->setFormatCode('0.00%'); + +$helper->log($worksheet->getCell('B7')->getValue()); +$helper->log('DISC() Result is ' . $worksheet->getCell('B7')->getFormattedValue()); diff --git a/samples/Calculations/Financial/DOLLARDE.php b/samples/Calculations/Financial/DOLLARDE.php new file mode 100644 index 00000000..d7187401 --- /dev/null +++ b/samples/Calculations/Financial/DOLLARDE.php @@ -0,0 +1,30 @@ +log('Returns the dollar value in fractional notation, into a dollar value expressed as a decimal.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + [1.01, 16], + [1.1, 16], + [1.03, 32], + [1.3, 32], + [1.12, 32], +]; + +$worksheet->fromArray($arguments, null, 'A1'); + +// Now the formula +for ($row = 1; $row <= 5; ++$row) { + $worksheet->setCellValue("C{$row}", "=DOLLARDE(A{$row}, B{$row})"); + + $helper->log($worksheet->getCell("C{$row}")->getValue()); + $helper->log('DOLLARDE() Result is ' . $worksheet->getCell("C{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/DOLLARFR.php b/samples/Calculations/Financial/DOLLARFR.php new file mode 100644 index 00000000..75424be0 --- /dev/null +++ b/samples/Calculations/Financial/DOLLARFR.php @@ -0,0 +1,30 @@ +log('Returns the dollar value expressed as a decimal number, into a dollar price, expressed as a fraction.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + [1.0625, 16], + [1.625, 16], + [1.09375, 32], + [1.9375, 32], + [1.375, 32], +]; + +$worksheet->fromArray($arguments, null, 'A1'); + +// Now the formula +for ($row = 1; $row <= 5; ++$row) { + $worksheet->setCellValue("C{$row}", "=DOLLARFR(A{$row}, B{$row})"); + + $helper->log($worksheet->getCell("C{$row}")->getValue()); + $helper->log('DOLLARFR() Result is ' . $worksheet->getCell("C{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/EFFECT.php b/samples/Calculations/Financial/EFFECT.php new file mode 100644 index 00000000..a74f4500 --- /dev/null +++ b/samples/Calculations/Financial/EFFECT.php @@ -0,0 +1,31 @@ +log('Returns the effective annual interest rate for a given nominal interest rate and number of'); +$helper->log('compounding periods per year.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + [0.10, 4], + [0.10, 2], + [0.025, 2], +]; + +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B3')->getNumberFormat()->setFormatCode('0.00%'); + +// Now the formula +for ($row = 1; $row <= 3; ++$row) { + $worksheet->setCellValue("C{$row}", "=EFFECT(A{$row}, B{$row})"); + $worksheet->getStyle("C{$row}")->getNumberFormat()->setFormatCode('0.00%'); + + $helper->log($worksheet->getCell("C{$row}")->getValue()); + $helper->log('EFFECT() Result is ' . $worksheet->getCell("C{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/FV.php b/samples/Calculations/Financial/FV.php new file mode 100644 index 00000000..31ddb630 --- /dev/null +++ b/samples/Calculations/Financial/FV.php @@ -0,0 +1,36 @@ +log('Returns the Future Value of an investment with periodic constant payments and a constant interest rate.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Interest Rate', 0.05, 0.10], + ['Pament Frequency', 12, 4], + ['Duration (Years)', 5, 4], + ['Investment', -1000.00, -2000.00], + ['Payment Type', 0, 1], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:C1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B4:C4')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('B8', '=FV(B1/B2, B3*B2, B4)'); +$worksheet->setCellValue('C8', '=FV(C1/C2, C3*C2, C4, null, C5)'); +$worksheet->getStyle('B8:C8')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B8')->getValue()); +$helper->log('FV() Result is ' . $worksheet->getCell('B8')->getFormattedValue()); + +$helper->log($worksheet->getCell('C6')->getValue()); +$helper->log('FV() Result is ' . $worksheet->getCell('C8')->getFormattedValue()); diff --git a/samples/Calculations/Financial/FVSCHEDULE.php b/samples/Calculations/Financial/FVSCHEDULE.php new file mode 100644 index 00000000..dfd2abbc --- /dev/null +++ b/samples/Calculations/Financial/FVSCHEDULE.php @@ -0,0 +1,36 @@ +log('Returns the Future Value of an initial principal, after applying a series of compound interest rates.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Principal'], + [10000.00], + [null], + ['Schedule'], + [0.05], + [0.05], + [0.035], + [0.035], + [0.035], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('A2')->getNumberFormat()->setFormatCode('$#,##0.00'); +$worksheet->getStyle('A5:A9')->getNumberFormat()->setFormatCode('0.00%'); + +// Now the formula +$worksheet->setCellValue('B1', '=FVSCHEDULE(A2, A5:A9)'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B1')->getValue()); +$helper->log('FVSCHEDULE() Result is ' . $worksheet->getCell('B1')->getFormattedValue()); diff --git a/samples/Calculations/Financial/INTRATE.php b/samples/Calculations/Financial/INTRATE.php new file mode 100644 index 00000000..594fb6cb --- /dev/null +++ b/samples/Calculations/Financial/INTRATE.php @@ -0,0 +1,32 @@ +log('Returns the interest rate for a fully invested security.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Settlement Date', DateHelper::getDateValue('01-Apr-2005')], + ['Maturity Date', DateHelper::getDateValue('31-Mar-2010')], + ['Investment', 1000.00], + ['Investment', 2125.00], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B2')->getNumberFormat()->setFormatCode('dd-mmm-yyyy'); +$worksheet->getStyle('B3:B4')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('B7', '=INTRATE(B1, B2, B3, B4)'); +$worksheet->getStyle('B7')->getNumberFormat()->setFormatCode('0.00%'); + +$helper->log($worksheet->getCell('B7')->getValue()); +$helper->log('INTRATE() Result is ' . $worksheet->getCell('B7')->getFormattedValue()); diff --git a/samples/Calculations/Financial/IPMT.php b/samples/Calculations/Financial/IPMT.php new file mode 100644 index 00000000..138ec378 --- /dev/null +++ b/samples/Calculations/Financial/IPMT.php @@ -0,0 +1,37 @@ +log('Returns the interest payment, during a specific period of a loan or investment that is paid in,'); +$helper->log('constant periodic payments, with a constant interest rate.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Interest Rate', 0.05], + ['Number of Years', 5], + ['Present Value', 50000.00], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B3')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$baseRow = 6; +for ($month = 1; $month <= 12; ++$month) { + $row = (string) ($baseRow + $month); + + $worksheet->setCellValue("A{$row}", "Payment for Mth {$month}"); + $worksheet->setCellValue("B{$row}", "=IPMT(\$B\$1/12, {$month}, \$B\$2*12, \$B\$3)"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("IPMT() Month {$month} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/IRR.php b/samples/Calculations/Financial/IRR.php new file mode 100644 index 00000000..e489af93 --- /dev/null +++ b/samples/Calculations/Financial/IRR.php @@ -0,0 +1,38 @@ +log('Returns the Internal Rate of Return for a supplied series of periodic cash flows.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Initial Investment', -100.00], + ['Year 1 Income', 20.00], + ['Year 2 Income', 24.00, 'IRR after 3 Years'], + ['Year 3 Income', 28.80], + ['Year 4 Income', 34.56, 'IRR after 5 Years'], + ['Year 5 Income', 41.47], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B6')->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('C4', '=IRR(B1:B4)'); +$worksheet->getStyle('C4')->getNumberFormat()->setFormatCode('0.00%'); + +$helper->log($worksheet->getCell('C4')->getValue()); +$helper->log('IRR() Result is ' . $worksheet->getCell('C4')->getFormattedValue()); + +$worksheet->setCellValue('C6', '=IRR(B1:B6)'); +$worksheet->getStyle('C6')->getNumberFormat()->setFormatCode('0.00%'); + +$helper->log($worksheet->getCell('C6')->getValue()); +$helper->log('IRR() Result is ' . $worksheet->getCell('C6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/ISPMT.php b/samples/Calculations/Financial/ISPMT.php new file mode 100644 index 00000000..cbede7ce --- /dev/null +++ b/samples/Calculations/Financial/ISPMT.php @@ -0,0 +1,36 @@ +log('Returns the interest paid during a specific period of a loan or investment.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Interest Rate', 0.05], + ['Number of Years', 5], + ['Present Value', 50000.00], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B3')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$baseRow = 6; +for ($month = 1; $month <= 12; ++$month) { + $row = (string) ($baseRow + $month); + + $worksheet->setCellValue("A{$row}", "Payment for Mth {$month}"); + $worksheet->setCellValue("B{$row}", "=ISPMT(\$B\$1/12, {$month}, \$B\$2*12, \$B\$3)"); + $worksheet->getStyle("B{$row}")->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); + + $helper->log($worksheet->getCell("B{$row}")->getValue()); + $helper->log("ISPMT() Month {$month} Result is " . $worksheet->getCell("B{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/MIRR.php b/samples/Calculations/Financial/MIRR.php new file mode 100644 index 00000000..313e10bd --- /dev/null +++ b/samples/Calculations/Financial/MIRR.php @@ -0,0 +1,42 @@ +log('Returns the Modified Internal Rate of Return for a supplied series of periodic cash flows.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Initial Investment', -100.00], + ['Year 1 Income', 18.00], + ['Year 2 Income', 22.50, 'MIRR after 3 Years'], + ['Year 3 Income', 28.00], + ['Year 4 Income', 35.50, 'MIRR after 5 Years'], + ['Year 5 Income', 45.00], + [null], + ['Finance Rate', 0.055], + ['Re-invest Rate', 0.05], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B6')->getNumberFormat()->setFormatCode('$#,##0.00;-$#,##0.00'); +$worksheet->getStyle('B8:B9')->getNumberFormat()->setFormatCode('0.00%'); + +// Now the formula +$worksheet->setCellValue('C4', '=MIRR(B1:B4, B8, B9)'); +$worksheet->getStyle('C4')->getNumberFormat()->setFormatCode('0.00%'); + +$helper->log($worksheet->getCell('C4')->getValue()); +$helper->log('MIRR() Result is ' . $worksheet->getCell('C4')->getFormattedValue()); + +$worksheet->setCellValue('C6', '=MIRR(B1:B6, B8, B9)'); +$worksheet->getStyle('C6')->getNumberFormat()->setFormatCode('0.00%'); + +$helper->log($worksheet->getCell('C6')->getValue()); +$helper->log('MIRR() Result is ' . $worksheet->getCell('C6')->getFormattedValue()); diff --git a/samples/Calculations/Financial/NOMINAL.php b/samples/Calculations/Financial/NOMINAL.php new file mode 100644 index 00000000..6b7951a1 --- /dev/null +++ b/samples/Calculations/Financial/NOMINAL.php @@ -0,0 +1,31 @@ +log('Returns the nominal interest rate for a given effective interest rate and number of'); +$helper->log('compounding periods per year.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + [0.10, 4], + [0.10, 2], + [0.025, 12], +]; + +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:B3')->getNumberFormat()->setFormatCode('0.00%'); + +// Now the formula +for ($row = 1; $row <= 3; ++$row) { + $worksheet->setCellValue("C{$row}", "=NOMINAL(A{$row}, B{$row})"); + $worksheet->getStyle("C{$row}")->getNumberFormat()->setFormatCode('0.00%'); + + $helper->log($worksheet->getCell("C{$row}")->getValue()); + $helper->log('NOMINAL() Result is ' . $worksheet->getCell("C{$row}")->getFormattedValue()); +} diff --git a/samples/Calculations/Financial/NPER.php b/samples/Calculations/Financial/NPER.php new file mode 100644 index 00000000..8acae473 --- /dev/null +++ b/samples/Calculations/Financial/NPER.php @@ -0,0 +1,39 @@ +log('Returns the number of periods required to pay off a loan, for a constant periodic payment'); +$helper->log('and a constant interest rate.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Interest Rate', 0.04, 0.06], + ['Payments per Year', 1, 4], + ['Payment Amount', -6000.00, -2000], + ['Present Value', 50000, 60000], + ['Future Value', null, 30000], + ['Payment Type', null, FinancialConstants::PAYMENT_BEGINNING_OF_PERIOD], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:C1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B3:C5')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +$worksheet->setCellValue('B8', '=NPER(B1/B2, B3, B4)'); + +$helper->log($worksheet->getCell('B8')->getValue()); +$helper->log('NPER() Result is ' . $worksheet->getCell('B8')->getFormattedValue()); + +$worksheet->setCellValue('C8', '=NPER(C1/C2, C3, C4, C5, C6)'); + +$helper->log($worksheet->getCell('C8')->getValue()); +$helper->log('NPER() Result is ' . $worksheet->getCell('C8')->getFormattedValue()); diff --git a/samples/Calculations/Financial/NPV.php b/samples/Calculations/Financial/NPV.php new file mode 100644 index 00000000..fa76d542 --- /dev/null +++ b/samples/Calculations/Financial/NPV.php @@ -0,0 +1,43 @@ +log('Returns the Net Present Value of an investment, based on a supplied discount rate,'); +$helper->log('and a series of future payments and income.'); + +// Create new PhpSpreadsheet object +$spreadsheet = new Spreadsheet(); +$worksheet = $spreadsheet->getActiveSheet(); + +// Add some data +$arguments = [ + ['Annual Discount Rate', 0.02, 0.05], + ['Initial Investment Cost', -5000.00, -10000], + ['Return from Year 1', 800.00, 2000.00], + ['Return from Year 2', 950.00, 2400.00], + ['Return from Year 3', 1080.00, 2900.00], + ['Return from Year 4', 1220.00, 3500.00], + ['Return from Year 5', 1500.00, 4100.00], +]; + +// Some basic formatting for the data +$worksheet->fromArray($arguments, null, 'A1'); +$worksheet->getStyle('B1:C1')->getNumberFormat()->setFormatCode('0.00%'); +$worksheet->getStyle('B2:C7')->getNumberFormat()->setFormatCode('$#,##0.00'); + +// Now the formula +// When initial investment is made at the end of the first period +$worksheet->setCellValue('B10', '=NPV(B1, B2:B7)'); +$worksheet->getStyle('B10')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('B10')->getValue()); +$helper->log('NPV() Result is ' . $worksheet->getCell('B10')->getFormattedValue()); + +// When initial investment is made at the start of the first period +$worksheet->setCellValue('C10', '=NPV(C1, C3:C7) + C2'); +$worksheet->getStyle('C10')->getNumberFormat()->setFormatCode('$#,##0.00'); + +$helper->log($worksheet->getCell('C10')->getValue()); +$helper->log('NPV() Result is ' . $worksheet->getCell('C10')->getFormattedValue()); diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index a11b8a12..32586b4c 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -855,7 +855,7 @@ class Calculation ], 'DISC' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'DISC'], + 'functionCall' => [Financial\Securities\Rates::class, 'discount'], 'argumentCount' => '4,5', ], 'DMAX' => [ @@ -1429,7 +1429,7 @@ class Calculation ], 'INTRATE' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'INTRATE'], + 'functionCall' => [Financial\Securities\Rates::class, 'interest'], 'argumentCount' => '4,5', ], 'IPMT' => [ @@ -2078,7 +2078,7 @@ class Calculation ], 'RECEIVED' => [ 'category' => Category::CATEGORY_FINANCIAL, - 'functionCall' => [Financial::class, 'RECEIVED'], + 'functionCall' => [Financial\Securities\Price::class, 'received'], 'argumentCount' => '4-5', ], 'REPLACE' => [ diff --git a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php index 636f0c87..5b3a8067 100644 --- a/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/DateTimeExcel/Helpers.php @@ -16,7 +16,7 @@ class Helpers * * @return bool TRUE if the year is a leap year, otherwise FALSE */ - public static function isLeapYear($year) + public static function isLeapYear($year): bool { return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0); } @@ -28,7 +28,7 @@ class Helpers * * @return float Excel date/time serial value */ - public static function getDateValue($dateValue, bool $allowBool = true) + public static function getDateValue($dateValue, bool $allowBool = true): float { if (is_object($dateValue)) { $retval = Date::PHPToExcel($dateValue); diff --git a/src/PhpSpreadsheet/Calculation/Financial.php b/src/PhpSpreadsheet/Calculation/Financial.php index ebf5cec1..9d933b4a 100644 --- a/src/PhpSpreadsheet/Calculation/Financial.php +++ b/src/PhpSpreadsheet/Calculation/Financial.php @@ -10,6 +10,9 @@ use PhpOffice\PhpSpreadsheet\Calculation\Financial\InterestRate; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; use PhpOffice\PhpSpreadsheet\Calculation\Financial\TreasuryBill; +/** + * @deprecated 1.18.0 + */ class Financial { const FINANCIAL_MAX_ITERATIONS = 128; @@ -30,24 +33,24 @@ class Financial * Use the periodic() method in the Financial\Securities\AccruedInterest class instead * * @param mixed $issue the security's issue date - * @param mixed $firstinterest the security's first interest date + * @param mixed $firstInterest the security's first interest date * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date * when the security is traded to the buyer. * @param mixed $rate the security's annual coupon rate - * @param mixed $par The security's par value. - * If you omit par, ACCRINT uses $1,000. + * @param mixed $parValue The security's par value. + * If you omit par, ACCRINT uses $1,000. * @param mixed $frequency The number of coupon payments per year. - * Valid frequency values are: - * 1 Annual - * 2 Semi-Annual - * 4 Quarterly + * Valid frequency values are: + * 1 Annual + * 2 Semi-Annual + * 4 Quarterly * @param mixed $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * @param mixed $calcMethod * If true, use Issue to Settlement * If false, use FirstInterest to Settlement @@ -56,20 +59,20 @@ class Financial */ public static function ACCRINT( $issue, - $firstinterest, + $firstInterest, $settlement, $rate, - $par = 1000, + $parValue = 1000, $frequency = 1, $basis = 0, $calcMethod = true ) { return Securities\AccruedInterest::periodic( $issue, - $firstinterest, + $firstInterest, $settlement, $rate, - $par, + $parValue, $frequency, $basis, $calcMethod @@ -92,20 +95,20 @@ class Financial * @param mixed $issue The security's issue date * @param mixed $settlement The security's settlement (or maturity) date * @param mixed $rate The security's annual coupon rate - * @param mixed $par The security's par value. - * If you omit par, ACCRINT uses $1,000. + * @param mixed $parValue The security's par value. + * If you omit par, ACCRINT uses $1,000. * @param mixed $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ - public static function ACCRINTM($issue, $settlement, $rate, $par = 1000, $basis = 0) + public static function ACCRINTM($issue, $settlement, $rate, $parValue = 1000, $basis = 0) { - return Securities\AccruedInterest::atMaturity($issue, $settlement, $rate, $par, $basis); + return Securities\AccruedInterest::atMaturity($issue, $settlement, $rate, $parValue, $basis); } /** @@ -170,11 +173,11 @@ class Financial * @param float $period The period * @param float $rate Rate of depreciation * @param int $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string (string containing the error type if there is an error) */ @@ -543,6 +546,11 @@ class Financial * Excel Function: * DISC(settlement,maturity,price,redemption[,basis]) * + * @Deprecated 1.18.0 + * + * @see Financial\Securities\Rates::discount() + * Use the discount() method in the Financial\Securities\Rates class instead + * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue * date when the security is traded to the buyer. @@ -561,30 +569,7 @@ class Financial */ public static function DISC($settlement, $maturity, $price, $redemption, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $price = Functions::flattenSingleValue($price); - $redemption = Functions::flattenSingleValue($redemption); - $basis = Functions::flattenSingleValue($basis); - - // Validate - if ((is_numeric($price)) && (is_numeric($redemption)) && (is_numeric($basis))) { - $price = (float) $price; - $redemption = (float) $redemption; - $basis = (int) $basis; - if (($price <= 0) || ($redemption <= 0)) { - return Functions::NAN(); - } - $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - - return (1 - $price / $redemption) / $daysBetweenSettlementAndMaturity; - } - - return Functions::VALUE(); + return Financial\Securities\Rates::discount($settlement, $maturity, $price, $redemption, $basis); } /** @@ -724,47 +709,30 @@ class Financial * Excel Function: * INTRATE(settlement,maturity,investment,redemption[,basis]) * + * @Deprecated 1.18.0 + * + * @see Financial\Securities\Rates::interest() + * Use the interest() method in the Financial\Securities\Rates class instead + * * @param mixed $settlement The security's settlement date. - * The security settlement date is the date after the issue date when the security is traded to the buyer. + * The security settlement date is the date after the issue 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. + * The maturity date is the date when the security expires. * @param int $investment the amount invested in the security * @param int $redemption the amount to be received at maturity * @param int $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string */ public static function INTRATE($settlement, $maturity, $investment, $redemption, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $investment = Functions::flattenSingleValue($investment); - $redemption = Functions::flattenSingleValue($redemption); - $basis = Functions::flattenSingleValue($basis); - - // Validate - if ((is_numeric($investment)) && (is_numeric($redemption)) && (is_numeric($basis))) { - $investment = (float) $investment; - $redemption = (float) $redemption; - $basis = (int) $basis; - if (($investment <= 0) || ($redemption <= 0)) { - return Functions::NAN(); - } - $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - - return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity); - } - - return Functions::VALUE(); + return Financial\Securities\Rates::interest($settlement, $maturity, $investment, $redemption, $basis); } /** @@ -1174,7 +1142,12 @@ class Financial /** * RECEIVED. * - * Returns the price per $100 face value of a discounted security. + * Returns the amount received at maturity for a fully invested Security. + * + * @Deprecated 1.18.0 + * + * @see Financial\Securities\Price::received() + * Use the received() method in the Financial\Securities\Price class instead * * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date when the security @@ -1194,27 +1167,7 @@ class Financial */ public static function RECEIVED($settlement, $maturity, $investment, $discount, $basis = 0) { - $settlement = Functions::flattenSingleValue($settlement); - $maturity = Functions::flattenSingleValue($maturity); - $investment = (float) Functions::flattenSingleValue($investment); - $discount = (float) Functions::flattenSingleValue($discount); - $basis = (int) Functions::flattenSingleValue($basis); - - // Validate - if ((is_numeric($investment)) && (is_numeric($discount)) && (is_numeric($basis))) { - if (($investment <= 0) || ($discount <= 0)) { - return Functions::NAN(); - } - $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); - if (!is_numeric($daysBetweenSettlementAndMaturity)) { - // return date error - return $daysBetweenSettlementAndMaturity; - } - - return $investment / (1 - ($discount * $daysBetweenSettlementAndMaturity)); - } - - return Functions::VALUE(); + return Financial\Securities\Price::received($settlement, $maturity, $investment, $discount, $basis); } /** diff --git a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php index 8b901872..2ea0f4fe 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Amortization.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Amortization.php @@ -4,12 +4,11 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Amortization { - use BaseValidations; - /** * AMORDEGRC. * @@ -40,24 +39,33 @@ class Amortization * * @return float|string (string containing the error type if there is an error) */ - public static function AMORDEGRC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0) - { + public static function AMORDEGRC( + $cost, + $purchased, + $firstPeriod, + $salvage, + $period, + $rate, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $cost = Functions::flattenSingleValue($cost); $purchased = Functions::flattenSingleValue($purchased); $firstPeriod = Functions::flattenSingleValue($firstPeriod); $salvage = Functions::flattenSingleValue($salvage); - $period = floor(Functions::flattenSingleValue($period)); + $period = Functions::flattenSingleValue($period); $rate = Functions::flattenSingleValue($rate); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $cost = self::validateFloat($cost); - $purchased = self::validateDate($purchased); - $firstPeriod = self::validateDate($firstPeriod); - $salvage = self::validateFloat($salvage); - $period = self::validateFloat($period); - $rate = self::validateFloat($rate); - $basis = self::validateBasis($basis); + $cost = FinancialValidations::validateFloat($cost); + $purchased = FinancialValidations::validateDate($purchased); + $firstPeriod = FinancialValidations::validateDate($firstPeriod); + $salvage = FinancialValidations::validateFloat($salvage); + $period = FinancialValidations::validateInt($period); + $rate = FinancialValidations::validateFloat($rate); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -118,24 +126,33 @@ class Amortization * * @return float|string (string containing the error type if there is an error) */ - public static function AMORLINC($cost, $purchased, $firstPeriod, $salvage, $period, $rate, $basis = 0) - { + public static function AMORLINC( + $cost, + $purchased, + $firstPeriod, + $salvage, + $period, + $rate, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $cost = Functions::flattenSingleValue($cost); $purchased = Functions::flattenSingleValue($purchased); $firstPeriod = Functions::flattenSingleValue($firstPeriod); $salvage = Functions::flattenSingleValue($salvage); $period = Functions::flattenSingleValue($period); $rate = Functions::flattenSingleValue($rate); - $basis = ($basis === null) ? 0 : (int) Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $cost = self::validateFloat($cost); - $purchased = self::validateDate($purchased); - $firstPeriod = self::validateDate($firstPeriod); - $salvage = self::validateFloat($salvage); - $period = self::validateFloat($period); - $rate = self::validateFloat($rate); - $basis = self::validateBasis($basis); + $cost = FinancialValidations::validateFloat($cost); + $purchased = FinancialValidations::validateDate($purchased); + $firstPeriod = FinancialValidations::validateDate($firstPeriod); + $salvage = FinancialValidations::validateFloat($salvage); + $period = FinancialValidations::validateFloat($period); + $rate = FinancialValidations::validateFloat($rate); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -149,7 +166,10 @@ class Amortization return $yearFrac; } - if (($basis == 1) && ($yearFrac < 1) && (DateTimeExcel\Helpers::isLeapYear($purchasedYear))) { + if ( + ($basis == FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL) && + ($yearFrac < 1) && (DateTimeExcel\Helpers::isLeapYear($purchasedYear)) + ) { $yearFrac *= 365 / 366; } diff --git a/src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php deleted file mode 100644 index 01d9ab30..00000000 --- a/src/PhpSpreadsheet/Calculation/Financial/BaseValidations.php +++ /dev/null @@ -1,72 +0,0 @@ - 4)) { - throw new Exception(Functions::NAN()); - } - - return $basis; - } -} diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/CashFlowValidations.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/CashFlowValidations.php new file mode 100644 index 00000000..fde68860 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/CashFlowValidations.php @@ -0,0 +1,56 @@ +getMessage(); } - // Validate parameters - if ($numberOfPeriods < 0 || ($type !== 0 && $type !== 1)) { - return Functions::NAN(); - } - return self::calculateFutureValue($rate, $numberOfPeriods, $payment, $presentValue, $type); } @@ -70,26 +69,31 @@ class Periodic * * @return float|string Result, or a string containing an error */ - public static function presentValue($rate, $numberOfPeriods, $payment = 0, $futureValue = 0, $type = 0) - { + public static function presentValue( + $rate, + $numberOfPeriods, + $payment = 0.0, + $futureValue = 0.0, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD + ) { $rate = Functions::flattenSingleValue($rate); $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); $payment = ($payment === null) ? 0.0 : Functions::flattenSingleValue($payment); $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $rate = self::validateFloat($rate); - $numberOfPeriods = self::validateInt($numberOfPeriods); - $payment = self::validateFloat($payment); - $futureValue = self::validateFloat($futureValue); - $type = self::validateInt($type); + $rate = CashFlowValidations::validateRate($rate); + $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods); + $payment = CashFlowValidations::validateFloat($payment); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } // Validate parameters - if ($numberOfPeriods < 0 || ($type !== 0 && $type !== 1)) { + if ($numberOfPeriods < 0) { return Functions::NAN(); } @@ -109,26 +113,31 @@ class Periodic * * @return float|string Result, or a string containing an error */ - public static function periods($rate, $payment, $presentValue, $futureValue = 0, $type = 0) - { + public static function periods( + $rate, + $payment, + $presentValue, + $futureValue = 0.0, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD + ) { $rate = Functions::flattenSingleValue($rate); $payment = Functions::flattenSingleValue($payment); $presentValue = Functions::flattenSingleValue($presentValue); $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $rate = self::validateFloat($rate); - $payment = self::validateFloat($payment); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); - $type = self::validateInt($type); + $rate = CashFlowValidations::validateRate($rate); + $payment = CashFlowValidations::validateFloat($payment); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } // Validate parameters - if ($payment == 0.0 || ($type != 0 && $type != 1)) { + if ($payment == 0.0) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php index 4f6ed170..b7f6011c 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Cumulative.php @@ -3,14 +3,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\Constant\Periodic; use PhpOffice\PhpSpreadsheet\Calculation\Exception; -use PhpOffice\PhpSpreadsheet\Calculation\Financial; -use PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities\Constants; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\CashFlowValidations; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Cumulative { - use Financial\BaseValidations; - /** * CUMIPMT. * @@ -31,30 +29,33 @@ class Cumulative * * @return float|string */ - public static function interest($rate, $periods, $presentValue, $start, $end, $type = Constants::END_OF_PERIOD) - { + public static function interest( + $rate, + $periods, + $presentValue, + $start, + $end, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD + ) { $rate = Functions::flattenSingleValue($rate); $periods = Functions::flattenSingleValue($periods); $presentValue = Functions::flattenSingleValue($presentValue); $start = Functions::flattenSingleValue($start); $end = Functions::flattenSingleValue($end); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $rate = self::validateFloat($rate); - $periods = self::validateInt($periods); - $presentValue = self::validateFloat($presentValue); - $start = self::validateInt($start); - $end = self::validateInt($end); - $type = self::validateInt($type); + $rate = CashFlowValidations::validateRate($rate); + $periods = CashFlowValidations::validateInt($periods); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $start = CashFlowValidations::validateInt($start); + $end = CashFlowValidations::validateInt($end); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } // Validate parameters - if ($type !== Constants::END_OF_PERIOD && $type !== Constants::BEGINNING_OF_PERIOD) { - return Functions::NAN(); - } if ($start < 1 || $start > $end) { return Functions::NAN(); } @@ -93,30 +94,33 @@ class Cumulative * * @return float|string */ - public static function principal($rate, $periods, $presentValue, $start, $end, $type = 0) - { + public static function principal( + $rate, + $periods, + $presentValue, + $start, + $end, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD + ) { $rate = Functions::flattenSingleValue($rate); $periods = Functions::flattenSingleValue($periods); $presentValue = Functions::flattenSingleValue($presentValue); $start = Functions::flattenSingleValue($start); $end = Functions::flattenSingleValue($end); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $rate = self::validateFloat($rate); - $periods = self::validateInt($periods); - $presentValue = self::validateFloat($presentValue); - $start = self::validateInt($start); - $end = self::validateInt($end); - $type = self::validateInt($type); + $rate = CashFlowValidations::validateRate($rate); + $periods = CashFlowValidations::validateInt($periods); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $start = CashFlowValidations::validateInt($start); + $end = CashFlowValidations::validateInt($end); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } // Validate parameters - if ($type !== 0 && $type !== 1) { - return Functions::NAN(); - } if ($start < 1 || $start > $end) { return Functions::VALUE(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php index 3f579ce2..56d2e379 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Interest.php @@ -3,13 +3,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\Constant\Periodic; use PhpOffice\PhpSpreadsheet\Calculation\Exception; -use PhpOffice\PhpSpreadsheet\Calculation\Financial\BaseValidations; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\CashFlowValidations; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Interest { - use BaseValidations; - private const FINANCIAL_MAX_ITERATIONS = 128; private const FINANCIAL_PRECISION = 1.0e-08; @@ -32,30 +31,33 @@ class Interest * * @return float|string */ - public static function payment($interestRate, $period, $numberOfPeriods, $presentValue, $futureValue = 0, $type = 0) - { + public static function payment( + $interestRate, + $period, + $numberOfPeriods, + $presentValue, + $futureValue = 0, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD + ) { $interestRate = Functions::flattenSingleValue($interestRate); $period = Functions::flattenSingleValue($period); $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); $presentValue = Functions::flattenSingleValue($presentValue); - $futureValue = Functions::flattenSingleValue($futureValue); - $type = Functions::flattenSingleValue($type); + $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $interestRate = self::validateFloat($interestRate); - $period = self::validateInt($period); - $numberOfPeriods = self::validateInt($numberOfPeriods); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); - $type = self::validateInt($type); + $interestRate = CashFlowValidations::validateRate($interestRate); + $period = CashFlowValidations::validateInt($period); + $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } if ($period <= 0 || $period > $numberOfPeriods) { return Functions::NAN(); } @@ -94,17 +96,19 @@ class Interest $principleRemaining = Functions::flattenSingleValue($principleRemaining); try { - $interestRate = self::validateFloat($interestRate); - $period = self::validateInt($period); - $numberOfPeriods = self::validateInt($numberOfPeriods); - $principleRemaining = self::validateFloat($principleRemaining); + $interestRate = CashFlowValidations::validateRate($interestRate); + $period = CashFlowValidations::validateInt($period); + $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods); + $principleRemaining = CashFlowValidations::validateFloat($principleRemaining); } catch (Exception $e) { return $e->getMessage(); } + // Validate parameters if ($period <= 0 || $period > $numberOfPeriods) { return Functions::NAN(); } + // Return value $returnValue = 0; @@ -148,22 +152,28 @@ class Interest * * @return float|string */ - public static function rate($numberOfPeriods, $payment, $presentValue, $futureValue = 0.0, $type = 0, $guess = 0.1) - { + public static function rate( + $numberOfPeriods, + $payment, + $presentValue, + $futureValue = 0.0, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD, + $guess = 0.1 + ) { $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); $payment = Functions::flattenSingleValue($payment); $presentValue = Functions::flattenSingleValue($presentValue); $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); $guess = ($guess === null) ? 0.1 : Functions::flattenSingleValue($guess); try { - $numberOfPeriods = self::validateInt($numberOfPeriods); - $payment = self::validateFloat($payment); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); - $type = self::validateInt($type); - $guess = self::validateFloat($guess); + $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods); + $payment = CashFlowValidations::validateFloat($payment); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); + $type = CashFlowValidations::validatePeriodType($type); + $guess = CashFlowValidations::validateFloat($guess); } catch (Exception $e) { return $e->getMessage(); } @@ -188,7 +198,7 @@ class Interest private static function rateNextGuess($rate, $numberOfPeriods, $payment, $presentValue, $futureValue, $type) { - if ($rate == 0) { + if ($rate == 0.0) { return Functions::NAN(); } $tt1 = ($rate + 1) ** $numberOfPeriods; diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php index 5e76f346..ca989e00 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/InterestAndPrincipal.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\Constant\Periodic; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; + class InterestAndPrincipal { protected $interest; @@ -14,14 +16,14 @@ class InterestAndPrincipal int $numberOfPeriods = 0, float $presentValue = 0, float $futureValue = 0, - int $type = 0 + int $type = FinancialConstants::PAYMENT_END_OF_PERIOD ) { $payment = Payments::annuity($rate, $numberOfPeriods, $presentValue, $futureValue, $type); $capital = $presentValue; $interest = 0.0; $principal = 0.0; for ($i = 1; $i <= $period; ++$i) { - $interest = ($type && $i == 1) ? 0 : -$capital * $rate; + $interest = ($type === FinancialConstants::PAYMENT_BEGINNING_OF_PERIOD && $i == 1) ? 0 : -$capital * $rate; $principal = $payment - $interest; $capital += $principal; } diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php index a0c61586..e103f923 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Constant/Periodic/Payments.php @@ -3,13 +3,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\Constant\Periodic; use PhpOffice\PhpSpreadsheet\Calculation\Exception; -use PhpOffice\PhpSpreadsheet\Calculation\Financial\BaseValidations; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow\CashFlowValidations; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Payments { - use BaseValidations; - /** * PMT. * @@ -23,29 +22,29 @@ class Payments * * @return float|string Result, or a string containing an error */ - public static function annuity($interestRate, $numberOfPeriods, $presentValue, $futureValue = 0, $type = 0) - { + public static function annuity( + $interestRate, + $numberOfPeriods, + $presentValue, + $futureValue = 0, + $type = FinancialConstants::PAYMENT_END_OF_PERIOD + ) { $interestRate = Functions::flattenSingleValue($interestRate); $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); $presentValue = Functions::flattenSingleValue($presentValue); $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $interestRate = self::validateFloat($interestRate); - $numberOfPeriods = self::validateInt($numberOfPeriods); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); - $type = self::validateInt($type); + $interestRate = CashFlowValidations::validateRate($interestRate); + $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } - // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } - // Calculate if ($interestRate != 0.0) { return (-$futureValue - $presentValue * (1 + $interestRate) ** $numberOfPeriods) / @@ -76,30 +75,27 @@ class Payments $numberOfPeriods, $presentValue, $futureValue = 0, - $type = 0 + $type = FinancialConstants::PAYMENT_END_OF_PERIOD ) { $interestRate = Functions::flattenSingleValue($interestRate); $period = Functions::flattenSingleValue($period); $numberOfPeriods = Functions::flattenSingleValue($numberOfPeriods); $presentValue = Functions::flattenSingleValue($presentValue); $futureValue = ($futureValue === null) ? 0.0 : Functions::flattenSingleValue($futureValue); - $type = ($type === null) ? 0 : Functions::flattenSingleValue($type); + $type = ($type === null) ? FinancialConstants::PAYMENT_END_OF_PERIOD : Functions::flattenSingleValue($type); try { - $interestRate = self::validateFloat($interestRate); - $period = self::validateInt($period); - $numberOfPeriods = self::validateInt($numberOfPeriods); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); - $type = self::validateInt($type); + $interestRate = CashFlowValidations::validateRate($interestRate); + $period = CashFlowValidations::validateInt($period); + $numberOfPeriods = CashFlowValidations::validateInt($numberOfPeriods); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); + $type = CashFlowValidations::validatePeriodType($type); } catch (Exception $e) { return $e->getMessage(); } // Validate parameters - if ($type != 0 && $type != 1) { - return Functions::NAN(); - } if ($period <= 0 || $period > $numberOfPeriods) { return Functions::NAN(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php index 9fecd755..a30634da 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php +++ b/src/PhpSpreadsheet/Calculation/Financial/CashFlow/Single.php @@ -3,13 +3,10 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\CashFlow; use PhpOffice\PhpSpreadsheet\Calculation\Exception; -use PhpOffice\PhpSpreadsheet\Calculation\Financial\BaseValidations; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Single { - use BaseValidations; - /** * FVSCHEDULE. * @@ -30,10 +27,10 @@ class Single $schedule = Functions::flattenArray($schedule); try { - $principal = self::validateFloat($principal); + $principal = CashFlowValidations::validateFloat($principal); foreach ($schedule as $rate) { - $rate = self::validateFloat($rate); + $rate = CashFlowValidations::validateFloat($rate); $principal *= 1 + $rate; } } catch (Exception $e) { @@ -48,22 +45,22 @@ class Single * * Calculates the number of periods required for an investment to reach a specified value. * - * @param float $rate Interest rate per period - * @param float $presentValue Present Value - * @param float $futureValue Future Value + * @param mixed $rate Interest rate per period + * @param mixed $presentValue Present Value + * @param mixed $futureValue Future Value * * @return float|string Result, or a string containing an error */ - public static function periods($rate = 0.0, $presentValue = 0.0, $futureValue = 0.0) + public static function periods($rate, $presentValue, $futureValue) { $rate = Functions::flattenSingleValue($rate); $presentValue = Functions::flattenSingleValue($presentValue); $futureValue = Functions::flattenSingleValue($futureValue); try { - $rate = self::validateFloat($rate); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); + $rate = CashFlowValidations::validateRate($rate); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); } catch (Exception $e) { return $e->getMessage(); } @@ -94,9 +91,9 @@ class Single $futureValue = Functions::flattenSingleValue($futureValue); try { - $periods = self::validateFloat($periods); - $presentValue = self::validateFloat($presentValue); - $futureValue = self::validateFloat($futureValue); + $periods = CashFlowValidations::validateFloat($periods); + $presentValue = CashFlowValidations::validatePresentValue($presentValue); + $futureValue = CashFlowValidations::validateFutureValue($futureValue); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Constants.php b/src/PhpSpreadsheet/Calculation/Financial/Constants.php new file mode 100644 index 00000000..17740b0a --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Constants.php @@ -0,0 +1,19 @@ +getMessage(); } @@ -68,7 +69,7 @@ class Coupons } $prev = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_PREVIOUS); - if ($basis === Helpers::DAYS_PER_YEAR_ACTUAL) { + if ($basis === FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL) { return abs(DateTimeExcel\Days::funcDays($prev, $settlement)); } @@ -102,30 +103,36 @@ class Coupons * * @return float|string */ - public static function COUPDAYS($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) - { + public static function COUPDAYS( + $settlement, + $maturity, + $frequency, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $frequency = Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); self::validateCouponPeriod($settlement, $maturity); - $frequency = self::validateFrequency($frequency); - $basis = self::validateBasis($basis); + $frequency = FinancialValidations::validateFrequency($frequency); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } switch ($basis) { - case Helpers::DAYS_PER_YEAR_365: + case FinancialConstants::BASIS_DAYS_PER_YEAR_365: // Actual/365 return 365 / $frequency; - case Helpers::DAYS_PER_YEAR_ACTUAL: + case FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL: // Actual/actual - if ($frequency == self::FREQUENCY_ANNUAL) { + if ($frequency == FinancialConstants::FREQUENCY_ANNUAL) { $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); return $daysPerYear / $frequency; @@ -167,19 +174,25 @@ class Coupons * * @return float|string */ - public static function COUPDAYSNC($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) - { + public static function COUPDAYSNC( + $settlement, + $maturity, + $frequency, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $frequency = Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); self::validateCouponPeriod($settlement, $maturity); - $frequency = self::validateFrequency($frequency); - $basis = self::validateBasis($basis); + $frequency = FinancialValidations::validateFrequency($frequency); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -187,7 +200,7 @@ class Coupons $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($settlement), $basis); $next = self::couponFirstPeriodDate($settlement, $maturity, $frequency, self::PERIOD_DATE_NEXT); - if ($basis === Helpers::DAYS_PER_YEAR_NASD) { + if ($basis === FinancialConstants::BASIS_DAYS_PER_YEAR_NASD) { $settlementDate = Date::excelToDateTimeObject($settlement); $settlementEoM = Helpers::isLastDayOfMonth($settlementDate); if ($settlementEoM) { @@ -226,19 +239,25 @@ class Coupons * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag */ - public static function COUPNCD($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) - { + public static function COUPNCD( + $settlement, + $maturity, + $frequency, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $frequency = Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); self::validateCouponPeriod($settlement, $maturity); - $frequency = self::validateFrequency($frequency); - $basis = self::validateBasis($basis); + $frequency = FinancialValidations::validateFrequency($frequency); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -274,19 +293,25 @@ class Coupons * * @return int|string */ - public static function COUPNUM($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) - { + public static function COUPNUM( + $settlement, + $maturity, + $frequency, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $frequency = Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); self::validateCouponPeriod($settlement, $maturity); - $frequency = self::validateFrequency($frequency); - $basis = self::validateBasis($basis); + $frequency = FinancialValidations::validateFrequency($frequency); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -294,7 +319,7 @@ class Coupons $yearsBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac( $settlement, $maturity, - Helpers::DAYS_PER_YEAR_NASD + FinancialConstants::BASIS_DAYS_PER_YEAR_NASD ); return (int) ceil($yearsBetweenSettlementAndMaturity * $frequency); @@ -328,19 +353,25 @@ class Coupons * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object, * depending on the value of the ReturnDateType flag */ - public static function COUPPCD($settlement, $maturity, $frequency, $basis = Helpers::DAYS_PER_YEAR_NASD) - { + public static function COUPPCD( + $settlement, + $maturity, + $frequency, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $frequency = Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); self::validateCouponPeriod($settlement, $maturity); - $frequency = self::validateFrequency($frequency); - $basis = self::validateBasis($basis); + $frequency = FinancialValidations::validateFrequency($frequency); + $basis = FinancialValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php index a918bf7d..650a4861 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Depreciation.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Depreciation { - use BaseValidations; - /** * DB. * @@ -127,7 +125,10 @@ class Depreciation $previousDepreciation = 0; $depreciation = 0; for ($per = 1; $per <= $period; ++$per) { - $depreciation = min(($cost - $previousDepreciation) * ($factor / $life), ($cost - $salvage - $previousDepreciation)); + $depreciation = min( + ($cost - $previousDepreciation) * ($factor / $life), + ($cost - $salvage - $previousDepreciation) + ); $previousDepreciation += $depreciation; } @@ -205,7 +206,7 @@ class Depreciation private static function validateCost($cost, bool $negativeValueAllowed = false): float { - $cost = self::validateFloat($cost); + $cost = FinancialValidations::validateFloat($cost); if ($cost < 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -215,7 +216,7 @@ class Depreciation private static function validateSalvage($salvage, bool $negativeValueAllowed = false): float { - $salvage = self::validateFloat($salvage); + $salvage = FinancialValidations::validateFloat($salvage); if ($salvage < 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -225,7 +226,7 @@ class Depreciation private static function validateLife($life, bool $negativeValueAllowed = false): float { - $life = self::validateFloat($life); + $life = FinancialValidations::validateFloat($life); if ($life < 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -235,7 +236,7 @@ class Depreciation private static function validatePeriod($period, bool $negativeValueAllowed = false): float { - $period = self::validateFloat($period); + $period = FinancialValidations::validateFloat($period); if ($period <= 0.0 && $negativeValueAllowed === false) { throw new Exception(Functions::NAN()); } @@ -245,7 +246,7 @@ class Depreciation private static function validateMonth($month): int { - $month = self::validateInt($month); + $month = FinancialValidations::validateInt($month); if ($month < 1) { throw new Exception(Functions::NAN()); } @@ -255,7 +256,7 @@ class Depreciation private static function validateFactor($factor): float { - $factor = self::validateFloat($factor); + $factor = FinancialValidations::validateFloat($factor); if ($factor <= 0.0) { throw new Exception(Functions::NAN()); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Financial/FinancialValidations.php similarity index 51% rename from src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php rename to src/PhpSpreadsheet/Calculation/Financial/FinancialValidations.php index bd197d7f..310e0051 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/BaseValidations.php +++ b/src/PhpSpreadsheet/Calculation/Financial/FinancialValidations.php @@ -1,20 +1,42 @@ = $maturity) { - throw new Exception(Functions::NAN()); + if (!is_numeric($value)) { + throw new Exception(Functions::VALUE()); } + + return (int) floor((float) $value); } - protected static function validateRate($rate): float + /** + * @param mixed $rate + */ + public static function validateRate($rate): float { $rate = self::validateFloat($rate); if ($rate < 0.0) { @@ -55,67 +70,16 @@ trait BaseValidations return $rate; } - protected static function validateParValue($parValue): float + /** + * @param mixed $frequency + */ + public static function validateFrequency($frequency): int { - $parValue = self::validateFloat($parValue); - if ($parValue < 0.0) { - throw new Exception(Functions::NAN()); - } - - return $parValue; - } - - protected static function validatePrice($price): float - { - $price = self::validateFloat($price); - if ($price < 0.0) { - throw new Exception(Functions::NAN()); - } - - return $price; - } - - protected static function validateYield($yield): float - { - $yield = self::validateFloat($yield); - if ($yield < 0.0) { - throw new Exception(Functions::NAN()); - } - - return $yield; - } - - protected static function validateRedemption($redemption): float - { - $redemption = self::validateFloat($redemption); - if ($redemption <= 0.0) { - throw new Exception(Functions::NAN()); - } - - return $redemption; - } - - protected static function validateDiscount($discount): float - { - $discount = self::validateFloat($discount); - if ($discount <= 0.0) { - throw new Exception(Functions::NAN()); - } - - return $discount; - } - - protected static function validateFrequency($frequency): int - { - if (!is_numeric($frequency)) { - throw new Exception(Functions::VALUE()); - } - - $frequency = (int) $frequency; + $frequency = self::validateInt($frequency); if ( - ($frequency !== SecuritiesConstants::FREQUENCY_ANNUAL) && - ($frequency !== SecuritiesConstants::FREQUENCY_SEMI_ANNUAL) && - ($frequency !== SecuritiesConstants::FREQUENCY_QUARTERLY) + ($frequency !== FinancialConstants::FREQUENCY_ANNUAL) && + ($frequency !== FinancialConstants::FREQUENCY_SEMI_ANNUAL) && + ($frequency !== FinancialConstants::FREQUENCY_QUARTERLY) ) { throw new Exception(Functions::NAN()); } @@ -123,7 +87,10 @@ trait BaseValidations return $frequency; } - protected static function validateBasis($basis): int + /** + * @param mixed $basis + */ + public static function validateBasis($basis): int { if (!is_numeric($basis)) { throw new Exception(Functions::VALUE()); @@ -136,4 +103,56 @@ trait BaseValidations return $basis; } + + /** + * @param mixed $price + */ + public static function validatePrice($price): float + { + $price = self::validateFloat($price); + if ($price < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $price; + } + + /** + * @param mixed $parValue + */ + public static function validateParValue($parValue): float + { + $parValue = self::validateFloat($parValue); + if ($parValue < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $parValue; + } + + /** + * @param mixed $yield + */ + public static function validateYield($yield): float + { + $yield = self::validateFloat($yield); + if ($yield < 0.0) { + throw new Exception(Functions::NAN()); + } + + return $yield; + } + + /** + * @param mixed $discount + */ + public static function validateDiscount($discount): float + { + $discount = self::validateFloat($discount); + if ($discount <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $discount; + } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Helpers.php b/src/PhpSpreadsheet/Calculation/Financial/Helpers.php index 79ef61e3..d339b134 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Helpers.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Helpers.php @@ -4,16 +4,11 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; use DateTimeInterface; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Helpers { - public const DAYS_PER_YEAR_NASD = 0; - public const DAYS_PER_YEAR_ACTUAL = 1; - public const DAYS_PER_YEAR_360 = 2; - public const DAYS_PER_YEAR_365 = 3; - public const DAYS_PER_YEAR_360_EUROPEAN = 4; - /** * daysPerYear. * @@ -21,11 +16,11 @@ class Helpers * * @param int|string $year The year against which we're testing * @param int|string $basis The type of day count: - * 0 or omitted US (NASD) 360 - * 1 Actual (365 or 366 in a leap year) - * 2 360 - * 3 365 - * 4 European 360 + * 0 or omitted US (NASD) 360 + * 1 Actual (365 or 366 in a leap year) + * 2 360 + * 3 365 + * 4 European 360 * * @return int|string Result, or a string containing an error */ @@ -36,13 +31,13 @@ class Helpers } switch ($basis) { - case self::DAYS_PER_YEAR_NASD: - case self::DAYS_PER_YEAR_360: - case self::DAYS_PER_YEAR_360_EUROPEAN: + case FinancialConstants::BASIS_DAYS_PER_YEAR_NASD: + case FinancialConstants::BASIS_DAYS_PER_YEAR_360: + case FinancialConstants::BASIS_DAYS_PER_YEAR_360_EUROPEAN: return 360; - case self::DAYS_PER_YEAR_365: + case FinancialConstants::BASIS_DAYS_PER_YEAR_365: return 365; - case self::DAYS_PER_YEAR_ACTUAL: + case FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL: return (DateTimeExcel\Helpers::isLeapYear($year)) ? 366 : 365; } @@ -55,10 +50,8 @@ class Helpers * Returns a boolean TRUE/FALSE indicating if this date is the last date of the month * * @param DateTimeInterface $date The date for testing - * - * @return bool */ - public static function isLastDayOfMonth(DateTimeInterface $date) + public static function isLastDayOfMonth(DateTimeInterface $date): bool { return $date->format('d') === $date->format('t'); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php index 7d66c891..72df31e1 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php +++ b/src/PhpSpreadsheet/Calculation/Financial/InterestRate.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class InterestRate { - use BaseValidations; - /** * EFFECT. * @@ -29,8 +27,8 @@ class InterestRate $periodsPerYear = Functions::flattenSingleValue($periodsPerYear); try { - $nominalRate = self::validateFloat($nominalRate); - $periodsPerYear = self::validateInt($periodsPerYear); + $nominalRate = FinancialValidations::validateFloat($nominalRate); + $periodsPerYear = FinancialValidations::validateInt($periodsPerYear); } catch (Exception $e) { return $e->getMessage(); } @@ -58,8 +56,8 @@ class InterestRate $periodsPerYear = Functions::flattenSingleValue($periodsPerYear); try { - $effectiveRate = self::validateFloat($effectiveRate); - $periodsPerYear = self::validateInt($periodsPerYear); + $effectiveRate = FinancialValidations::validateFloat($effectiveRate); + $periodsPerYear = FinancialValidations::validateInt($periodsPerYear); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php index 1875b8b7..004b47f3 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/AccruedInterest.php @@ -4,12 +4,11 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\YearFrac; use PhpOffice\PhpSpreadsheet\Calculation\Exception; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class AccruedInterest { - use BaseValidations; - public const ACCRINT_CALCMODE_ISSUE_TO_SETTLEMENT = true; public const ACCRINT_CALCMODE_FIRST_INTEREST_TO_SETTLEMENT = false; @@ -23,7 +22,7 @@ class AccruedInterest * ACCRINT(issue,firstinterest,settlement,rate,par,frequency[,basis][,calc_method]) * * @param mixed $issue the security's issue date - * @param mixed $firstinterest the security's first interest date + * @param mixed $firstInterest the security's first interest date * @param mixed $settlement The security's settlement date. * The security settlement date is the date after the issue date * when the security is traded to the buyer. @@ -47,30 +46,34 @@ class AccruedInterest */ public static function periodic( $issue, - $firstinterest, + $firstInterest, $settlement, $rate, $parValue = 1000, - $frequency = 1, - $basis = 0, + $frequency = FinancialConstants::FREQUENCY_ANNUAL, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD, $calcMethod = self::ACCRINT_CALCMODE_ISSUE_TO_SETTLEMENT ) { $issue = Functions::flattenSingleValue($issue); - $firstinterest = Functions::flattenSingleValue($firstinterest); + $firstInterest = Functions::flattenSingleValue($firstInterest); $settlement = Functions::flattenSingleValue($settlement); $rate = Functions::flattenSingleValue($rate); $parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue); - $frequency = ($frequency === null) ? 1 : Functions::flattenSingleValue($frequency); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $frequency = ($frequency === null) + ? FinancialConstants::FREQUENCY_ANNUAL + : Functions::flattenSingleValue($frequency); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $issue = self::validateIssueDate($issue); - $settlement = self::validateSettlementDate($settlement); - self::validateSecurityPeriod($issue, $settlement); - $rate = self::validateRate($rate); - $parValue = self::validateParValue($parValue); - $frequency = self::validateFrequency($frequency); - $basis = self::validateBasis($basis); + $issue = SecurityValidations::validateIssueDate($issue); + $settlement = SecurityValidations::validateSettlementDate($settlement); + SecurityValidations::validateSecurityPeriod($issue, $settlement); + $rate = SecurityValidations::validateRate($rate); + $parValue = SecurityValidations::validateParValue($parValue); + $frequency = SecurityValidations::validateFrequency($frequency); + $basis = SecurityValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -80,7 +83,7 @@ class AccruedInterest // return date error return $daysBetweenIssueAndSettlement; } - $daysBetweenFirstInterestAndSettlement = YearFrac::funcYearFrac($firstinterest, $settlement, $basis); + $daysBetweenFirstInterestAndSettlement = YearFrac::funcYearFrac($firstInterest, $settlement, $basis); if (!is_numeric($daysBetweenFirstInterestAndSettlement)) { // return date error return $daysBetweenFirstInterestAndSettlement; @@ -101,7 +104,7 @@ class AccruedInterest * @param mixed $settlement The security's settlement (or maturity) date * @param mixed $rate The security's annual coupon rate * @param mixed $parValue The security's par value. - * If you omit par, ACCRINT uses $1,000. + * If you omit parValue, ACCRINT uses $1,000. * @param mixed $basis The type of day count to use. * 0 or omitted US (NASD) 30/360 * 1 Actual/actual @@ -111,21 +114,28 @@ class AccruedInterest * * @return float|string Result, or a string containing an error */ - public static function atMaturity($issue, $settlement, $rate, $parValue = 1000, $basis = 0) - { + public static function atMaturity( + $issue, + $settlement, + $rate, + $parValue = 1000, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $issue = Functions::flattenSingleValue($issue); $settlement = Functions::flattenSingleValue($settlement); $rate = Functions::flattenSingleValue($rate); $parValue = ($parValue === null) ? 1000 : Functions::flattenSingleValue($parValue); - $basis = ($basis === null) ? 0 : Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $issue = self::validateIssueDate($issue); - $settlement = self::validateSettlementDate($settlement); - self::validateSecurityPeriod($issue, $settlement); - $rate = self::validateRate($rate); - $parValue = self::validateParValue($parValue); - $basis = self::validateBasis($basis); + $issue = SecurityValidations::validateIssueDate($issue); + $settlement = SecurityValidations::validateSettlementDate($settlement); + SecurityValidations::validateSecurityPeriod($issue, $settlement); + $rate = SecurityValidations::validateRate($rate); + $parValue = SecurityValidations::validateParValue($parValue); + $basis = SecurityValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php deleted file mode 100644 index f7bc2731..00000000 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Constants.php +++ /dev/null @@ -1,13 +0,0 @@ -getMessage(); } @@ -100,21 +108,28 @@ class Price * * @return float|string Result, or a string containing an error */ - public static function priceDiscounted($settlement, $maturity, $discount, $redemption, $basis = 0) - { + public static function priceDiscounted( + $settlement, + $maturity, + $discount, + $redemption, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $discount = Functions::flattenSingleValue($discount); $redemption = Functions::flattenSingleValue($redemption); - $basis = Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); - self::validateSecurityPeriod($settlement, $maturity); - $discount = self::validateDiscount($discount); - $redemption = self::validateRedemption($redemption); - $basis = self::validateBasis($basis); + $settlement = SecurityValidations::validateSettlementDate($settlement); + $maturity = SecurityValidations::validateMaturityDate($maturity); + SecurityValidations::validateSecurityPeriod($settlement, $maturity); + $discount = SecurityValidations::validateDiscount($discount); + $redemption = SecurityValidations::validateRedemption($redemption); + $basis = SecurityValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -150,23 +165,31 @@ class Price * * @return float|string Result, or a string containing an error */ - public static function priceAtMaturity($settlement, $maturity, $issue, $rate, $yield, $basis = 0) - { + public static function priceAtMaturity( + $settlement, + $maturity, + $issue, + $rate, + $yield, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $issue = Functions::flattenSingleValue($issue); $rate = Functions::flattenSingleValue($rate); $yield = Functions::flattenSingleValue($yield); - $basis = Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); - self::validateSecurityPeriod($settlement, $maturity); - $issue = self::validateIssueDate($issue); - $rate = self::validateRate($rate); - $yield = self::validateYield($yield); - $basis = self::validateBasis($basis); + $settlement = SecurityValidations::validateSettlementDate($settlement); + $maturity = SecurityValidations::validateMaturityDate($maturity); + SecurityValidations::validateSecurityPeriod($settlement, $maturity); + $issue = SecurityValidations::validateIssueDate($issue); + $rate = SecurityValidations::validateRate($rate); + $yield = SecurityValidations::validateYield($yield); + $basis = SecurityValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -198,4 +221,63 @@ class Price (1 + (($daysBetweenSettlementAndMaturity / $daysPerYear) * $yield)) - (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate * 100); } + + /** + * RECEIVED. + * + * Returns the amount received at maturity for a fully invested Security. + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue 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 mixed $investment The amount invested in the security + * @param mixed $discount The security's discount rate + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string Result, or a string containing an error + */ + public static function received( + $settlement, + $maturity, + $investment, + $discount, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $investment = Functions::flattenSingleValue($investment); + $discount = Functions::flattenSingleValue($discount); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); + + try { + $settlement = SecurityValidations::validateSettlementDate($settlement); + $maturity = SecurityValidations::validateMaturityDate($maturity); + SecurityValidations::validateSecurityPeriod($settlement, $maturity); + $investment = SecurityValidations::validateFloat($investment); + $discount = SecurityValidations::validateDiscount($discount); + $basis = SecurityValidations::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($investment <= 0) { + return Functions::NAN(); + } + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return $investment / (1 - ($discount * $daysBetweenSettlementAndMaturity)); + } } diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Rates.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Rates.php new file mode 100644 index 00000000..5a32d1d1 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Rates.php @@ -0,0 +1,137 @@ +getMessage(); + } + + if ($price <= 0.0) { + return Functions::NAN(); + } + + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return (1 - $price / $redemption) / $daysBetweenSettlementAndMaturity; + } + + /** + * INTRATE. + * + * Returns the interest rate for a fully invested security. + * + * Excel Function: + * INTRATE(settlement,maturity,investment,redemption[,basis]) + * + * @param mixed $settlement The security's settlement date. + * The security settlement date is the date after the issue 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 mixed $investment the amount invested in the security + * @param mixed $redemption the amount to be received at maturity + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 + * + * @return float|string + */ + public static function interest( + $settlement, + $maturity, + $investment, + $redemption, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { + $settlement = Functions::flattenSingleValue($settlement); + $maturity = Functions::flattenSingleValue($maturity); + $investment = Functions::flattenSingleValue($investment); + $redemption = Functions::flattenSingleValue($redemption); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); + + try { + $settlement = SecurityValidations::validateSettlementDate($settlement); + $maturity = SecurityValidations::validateMaturityDate($maturity); + SecurityValidations::validateSecurityPeriod($settlement, $maturity); + $investment = SecurityValidations::validateFloat($investment); + $redemption = SecurityValidations::validateRedemption($redemption); + $basis = SecurityValidations::validateBasis($basis); + } catch (Exception $e) { + return $e->getMessage(); + } + + if ($investment <= 0) { + return Functions::NAN(); + } + + $daysBetweenSettlementAndMaturity = DateTimeExcel\YearFrac::funcYearFrac($settlement, $maturity, $basis); + if (!is_numeric($daysBetweenSettlementAndMaturity)) { + // return date error + return $daysBetweenSettlementAndMaturity; + } + + return (($redemption / $investment) - 1) / ($daysBetweenSettlementAndMaturity); + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/SecurityValidations.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/SecurityValidations.php new file mode 100644 index 00000000..497197b8 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/SecurityValidations.php @@ -0,0 +1,42 @@ += $maturity) { + throw new Exception(Functions::NAN()); + } + } + + /** + * @param mixed $redemption + */ + public static function validateRedemption($redemption): float + { + $redemption = self::validateFloat($redemption); + if ($redemption <= 0.0) { + throw new Exception(Functions::NAN()); + } + + return $redemption; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php index 46c3bb05..bdd638fa 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php +++ b/src/PhpSpreadsheet/Calculation/Financial/Securities/Yields.php @@ -4,13 +4,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial\Securities; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Financial\Helpers; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Yields { - use BaseValidations; - /** * YIELDDISC. * @@ -21,32 +20,39 @@ class Yields * 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 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 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $price The security's price per $100 face value + * @param mixed $redemption The security's redemption value per $100 face value + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ - public static function yieldDiscounted($settlement, $maturity, $price, $redemption, $basis = 0) - { + public static function yieldDiscounted( + $settlement, + $maturity, + $price, + $redemption, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $price = Functions::flattenSingleValue($price); $redemption = Functions::flattenSingleValue($redemption); - $basis = (int) Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); - self::validateSecurityPeriod($settlement, $maturity); - $price = self::validatePrice($price); - $redemption = self::validateRedemption($redemption); - $basis = self::validateBasis($basis); + $settlement = SecurityValidations::validateSettlementDate($settlement); + $maturity = SecurityValidations::validateMaturityDate($maturity); + SecurityValidations::validateSecurityPeriod($settlement, $maturity); + $price = SecurityValidations::validatePrice($price); + $redemption = SecurityValidations::validateRedemption($redemption); + $basis = SecurityValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -76,34 +82,42 @@ class Yields * @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 int $basis The type of day count to use. - * 0 or omitted US (NASD) 30/360 - * 1 Actual/actual - * 2 Actual/360 - * 3 Actual/365 - * 4 European 30/360 + * @param mixed $rate The security's interest rate at date of issue + * @param mixed $price The security's price per $100 face value + * @param mixed $basis The type of day count to use. + * 0 or omitted US (NASD) 30/360 + * 1 Actual/actual + * 2 Actual/360 + * 3 Actual/365 + * 4 European 30/360 * * @return float|string Result, or a string containing an error */ - public static function yieldAtMaturity($settlement, $maturity, $issue, $rate, $price, $basis = 0) - { + public static function yieldAtMaturity( + $settlement, + $maturity, + $issue, + $rate, + $price, + $basis = FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + ) { $settlement = Functions::flattenSingleValue($settlement); $maturity = Functions::flattenSingleValue($maturity); $issue = Functions::flattenSingleValue($issue); $rate = Functions::flattenSingleValue($rate); $price = Functions::flattenSingleValue($price); - $basis = Functions::flattenSingleValue($basis); + $basis = ($basis === null) + ? FinancialConstants::BASIS_DAYS_PER_YEAR_NASD + : Functions::flattenSingleValue($basis); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); - self::validateSecurityPeriod($settlement, $maturity); - $issue = self::validateIssueDate($issue); - $rate = self::validateRate($rate); - $price = self::validatePrice($price); - $basis = self::validateBasis($basis); + $settlement = SecurityValidations::validateSettlementDate($settlement); + $maturity = SecurityValidations::validateMaturityDate($maturity); + SecurityValidations::validateSecurityPeriod($settlement, $maturity); + $issue = SecurityValidations::validateIssueDate($issue); + $rate = SecurityValidations::validateRate($rate); + $price = SecurityValidations::validatePrice($price); + $basis = SecurityValidations::validateBasis($basis); } catch (Exception $e) { return $e->getMessage(); } @@ -131,7 +145,8 @@ class Yields } $daysBetweenSettlementAndMaturity *= $daysPerYear; - return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / + return ((1 + (($daysBetweenIssueAndMaturity / $daysPerYear) * $rate) - + (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) / (($price / 100) + (($daysBetweenIssueAndSettlement / $daysPerYear) * $rate))) * ($daysPerYear / $daysBetweenSettlementAndMaturity); } diff --git a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php index 8f170488..31146c31 100644 --- a/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php +++ b/src/PhpSpreadsheet/Calculation/Financial/TreasuryBill.php @@ -4,12 +4,11 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Financial; use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; use PhpOffice\PhpSpreadsheet\Calculation\Exception; +use PhpOffice\PhpSpreadsheet\Calculation\Financial\Constants as FinancialConstants; use PhpOffice\PhpSpreadsheet\Calculation\Functions; class TreasuryBill { - use BaseValidations; - /** * TBILLEQ. * @@ -31,29 +30,28 @@ class TreasuryBill $discount = Functions::flattenSingleValue($discount); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); + $discount = FinancialValidations::validateFloat($discount); } catch (Exception $e) { return $e->getMessage(); } - // Validate - if (is_numeric($discount)) { - if ($discount <= 0) { - return Functions::NAN(); - } - - $daysBetweenSettlementAndMaturity = $maturity - $settlement; - $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($maturity), Helpers::DAYS_PER_YEAR_ACTUAL); - - if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { - return Functions::NAN(); - } - - return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity); + if ($discount <= 0) { + return Functions::NAN(); } - return Functions::VALUE(); + $daysBetweenSettlementAndMaturity = $maturity - $settlement; + $daysPerYear = Helpers::daysPerYear( + DateTimeExcel\Year::funcYear($maturity), + FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL + ); + + if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { + return Functions::NAN(); + } + + return (365 * $discount) / (360 - $discount * $daysBetweenSettlementAndMaturity); } /** @@ -77,34 +75,33 @@ class TreasuryBill $discount = Functions::flattenSingleValue($discount); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); + $discount = FinancialValidations::validateFloat($discount); } catch (Exception $e) { return $e->getMessage(); } - // Validate - if (is_numeric($discount)) { - if ($discount <= 0) { - return Functions::NAN(); - } - - $daysBetweenSettlementAndMaturity = $maturity - $settlement; - $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($maturity), Helpers::DAYS_PER_YEAR_ACTUAL); - - if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { - return Functions::NAN(); - } - - $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); - if ($price < 0.0) { - return Functions::NAN(); - } - - return $price; + if ($discount <= 0) { + return Functions::NAN(); } - return Functions::VALUE(); + $daysBetweenSettlementAndMaturity = $maturity - $settlement; + $daysPerYear = Helpers::daysPerYear( + DateTimeExcel\Year::funcYear($maturity), + FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL + ); + + if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { + return Functions::NAN(); + } + + $price = 100 * (1 - (($discount * $daysBetweenSettlementAndMaturity) / 360)); + if ($price < 0.0) { + return Functions::NAN(); + } + + return $price; } /** @@ -128,28 +125,23 @@ class TreasuryBill $price = Functions::flattenSingleValue($price); try { - $settlement = self::validateSettlementDate($settlement); - $maturity = self::validateMaturityDate($maturity); + $settlement = FinancialValidations::validateSettlementDate($settlement); + $maturity = FinancialValidations::validateMaturityDate($maturity); + $price = FinancialValidations::validatePrice($price); } catch (Exception $e) { return $e->getMessage(); } - // Validate - if (is_numeric($price)) { - if ($price <= 0) { - return Functions::NAN(); - } + $daysBetweenSettlementAndMaturity = $maturity - $settlement; + $daysPerYear = Helpers::daysPerYear( + DateTimeExcel\Year::funcYear($maturity), + FinancialConstants::BASIS_DAYS_PER_YEAR_ACTUAL + ); - $daysBetweenSettlementAndMaturity = $maturity - $settlement; - $daysPerYear = Helpers::daysPerYear(DateTimeExcel\Year::funcYear($maturity), Helpers::DAYS_PER_YEAR_ACTUAL); - - if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { - return Functions::NAN(); - } - - return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity); + if ($daysBetweenSettlementAndMaturity > $daysPerYear || $daysBetweenSettlementAndMaturity < 0) { + return Functions::NAN(); } - return Functions::VALUE(); + return ((100 - $price) / $price) * (360 / $daysBetweenSettlementAndMaturity); } } diff --git a/tests/data/Calculation/Financial/ACCRINT.php b/tests/data/Calculation/Financial/ACCRINT.php index 1852e7e3..a7b508d1 100644 --- a/tests/data/Calculation/Financial/ACCRINT.php +++ b/tests/data/Calculation/Financial/ACCRINT.php @@ -13,11 +13,15 @@ return [ ], [ 15.5555555555559, - '2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, true, + '2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, null, + ], + [ + 15.5555555555559, + '2008-03-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, ], [ 7.22222222222222, - '2008-04-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, true, + '2008-04-05', '2008-08-31', '2008-05-01', 0.10, 1000, 2, 0, ], [ 200, @@ -29,15 +33,15 @@ return [ ], [ 32.363013698630134, - '2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 5000, 4, 3, 1, + '2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 5000, 4, 3, ], [ 6.472602739726027, - '2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 1000, 4, 3, 1, + '2012-01-01', '2012-03-31', '2012-02-15', 0.0525, 1000, 4, 3, ], [ 18.05555555555555, - '2017-08-05', '2017-11-10', '2017-10-10', 0.05, 2000, 4, 0, 1, + '2017-08-05', '2017-11-10', '2017-10-10', 0.05, 2000, 4, 0, ], [ '#NUM!', diff --git a/tests/data/Calculation/Financial/ACCRINTM.php b/tests/data/Calculation/Financial/ACCRINTM.php index e442b6f8..444e41f9 100644 --- a/tests/data/Calculation/Financial/ACCRINTM.php +++ b/tests/data/Calculation/Financial/ACCRINTM.php @@ -11,6 +11,10 @@ return [ 800, '2010-01-01', '2010-12-31', 0.08, 10000, ], + [ + 800, + '2010-01-01', '2010-12-31', 0.08, 10000, null, + ], [ 365.958904109589, '2012-01-01', '2013-02-15', 0.065, 5000, 3, diff --git a/tests/data/Calculation/Financial/AMORDEGRC.php b/tests/data/Calculation/Financial/AMORDEGRC.php index ef3ef1e0..fa546c8c 100644 --- a/tests/data/Calculation/Financial/AMORDEGRC.php +++ b/tests/data/Calculation/Financial/AMORDEGRC.php @@ -7,6 +7,14 @@ return [ 776, 2400, '2008-08-19', '2008-12-31', 300, 1, 0.15, 1, ], + [ + 776, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.15, 0, + ], + [ + 776, + 2400, '2008-08-19', '2008-12-31', 300, 1, 0.15, null, + ], [ 820, 2400, '2008-08-19', '2008-12-31', 300, 1, 0.2, 1, @@ -51,6 +59,10 @@ return [ 2813, 10000, '2012-03-01', '2012-12-31', 1500, 1, 0.3, 1, ], + [ + 0.0, + 500, '2012-03-01', '2012-12-31', 500, 3, 0.3, 1, + ], [ '#VALUE!', 'NaN', '2012-03-01', '2020-12-25', 20, 1, 0.2, 4, @@ -67,4 +79,20 @@ return [ '#VALUE!', 550, '2012-03-01', '2020-12-25', 'NaN', 1, 0.2, 4, ], + [ + '#VALUE!', + 550, '2012-03-01', '2020-12-25', 20, 'NaN', 0.2, 4, + ], + [ + '#VALUE!', + 550, '2012-03-01', '2020-12-25', 20, 1, 'NaN', 4, + ], + [ + '#VALUE!', + 550, '2012-03-01', '2020-12-25', 20, 1, 0.2, 'NaN', + ], + [ + '#NUM!', + 550, '2012-03-01', '2020-12-25', 20, 1, 0.2, 99, + ], ]; diff --git a/tests/data/Calculation/Financial/AMORLINC.php b/tests/data/Calculation/Financial/AMORLINC.php index 34485c8a..c0175536 100644 --- a/tests/data/Calculation/Financial/AMORLINC.php +++ b/tests/data/Calculation/Financial/AMORLINC.php @@ -11,6 +11,14 @@ return [ 576, 2400, '2008-08-19', '2008-12-31', 300, 2, 0.24, 1, ], + [ + 576, + 2400, '2008-08-19', '2008-12-31', 300, 2, 0.24, 0, + ], + [ + 576, + 2400, '2008-08-19', '2008-12-31', 300, 2, 0.24, null, + ], [ 30, 150, '2011-01-01', '2011-09-30', 20, 1, 0.2, 4, @@ -27,8 +35,36 @@ return [ 0.0, 150, '2011-01-01', '2011-09-30', 20, 5, 0.2, 4, ], + [ + '#VALUE!', + 'NaN', '2011-01-01', '2011-09-30', 20, 1, 0.2, 4, + ], + [ + '#VALUE!', + 150, '2011-01-01', 'notADate', 20, 1, 0.2, 4, + ], [ '#VALUE!', 150, 'notADate', '2011-09-30', 20, 1, 0.2, 4, ], + [ + '#VALUE!', + 150, '2011-01-01', '2011-09-30', 'NaN', 1, 0.2, 4, + ], + [ + '#VALUE!', + 150, '2011-01-01', '2011-09-30', 20, 'NaN', 0.2, 4, + ], + [ + '#VALUE!', + 150, '2011-01-01', '2011-09-30', 20, 1, 'NaN', 4, + ], + [ + '#VALUE!', + 150, '2011-01-01', '2011-09-30', 20, 1, 0.2, 'NaN', + ], + [ + '#NUM!', + 550, '2012-03-01', '2020-12-25', 20, 1, 0.2, 99, + ], ]; diff --git a/tests/data/Calculation/Financial/COUPDAYBS.php b/tests/data/Calculation/Financial/COUPDAYBS.php index 7a805fdf..260783fa 100644 --- a/tests/data/Calculation/Financial/COUPDAYBS.php +++ b/tests/data/Calculation/Financial/COUPDAYBS.php @@ -16,6 +16,13 @@ return [ '2012-10-25', 4, ], + [ + 66, + '2011-01-01', + '2012-10-25', + 4, + null, + ], [ 71, '2011-01-25', diff --git a/tests/data/Calculation/Financial/COUPDAYS.php b/tests/data/Calculation/Financial/COUPDAYS.php index 2cd2469c..c72d26c1 100644 --- a/tests/data/Calculation/Financial/COUPDAYS.php +++ b/tests/data/Calculation/Financial/COUPDAYS.php @@ -16,6 +16,13 @@ return [ '2012-10-25', 4, ], + [ + 90, + '2011-01-01', + '2012-10-25', + 4, + null, + ], [ 182.5, '25-Jan-2007', diff --git a/tests/data/Calculation/Financial/COUPDAYSNC.php b/tests/data/Calculation/Financial/COUPDAYSNC.php index 6a7c5bb5..ca611475 100644 --- a/tests/data/Calculation/Financial/COUPDAYSNC.php +++ b/tests/data/Calculation/Financial/COUPDAYSNC.php @@ -16,6 +16,13 @@ return [ '2012-10-25', 4, ], + [ + 24, + '2011-01-01', + '2012-10-25', + 4, + null, + ], [ '#VALUE!', 'Invalid Date', diff --git a/tests/data/Calculation/Financial/COUPNCD.php b/tests/data/Calculation/Financial/COUPNCD.php index 222c6aa5..8dee4c0a 100644 --- a/tests/data/Calculation/Financial/COUPNCD.php +++ b/tests/data/Calculation/Financial/COUPNCD.php @@ -16,6 +16,13 @@ return [ '2012-10-25', 4, ], + [ + 40568, + '2011-01-01', + '2012-10-25', + 4, + null, + ], [ '#VALUE!', 'Invalid Date', diff --git a/tests/data/Calculation/Financial/COUPNUM.php b/tests/data/Calculation/Financial/COUPNUM.php index 5af5fd7b..4cf0cc29 100644 --- a/tests/data/Calculation/Financial/COUPNUM.php +++ b/tests/data/Calculation/Financial/COUPNUM.php @@ -17,6 +17,13 @@ return [ 4, 0, ], + [ + 8, + '2011-01-01', + '2012-10-25', + 4, + null, + ], [ '#VALUE!', 'Invalid Date', diff --git a/tests/data/Calculation/Financial/COUPPCD.php b/tests/data/Calculation/Financial/COUPPCD.php index 07c00d19..e906f147 100644 --- a/tests/data/Calculation/Financial/COUPPCD.php +++ b/tests/data/Calculation/Financial/COUPPCD.php @@ -16,6 +16,13 @@ return [ '2012-10-25', 4, ], + [ + 40476, + '2011-01-01', + '2012-10-25', + 4, + null, + ], [ '#VALUE!', 'Invalid Date', diff --git a/tests/data/Calculation/Financial/CUMIPMT.php b/tests/data/Calculation/Financial/CUMIPMT.php index d9a16a8b..2ccc5ff2 100644 --- a/tests/data/Calculation/Financial/CUMIPMT.php +++ b/tests/data/Calculation/Financial/CUMIPMT.php @@ -21,6 +21,15 @@ return [ 1, 0, ], + [ + -937.5, + 0.0075, + 360, + 125000, + 1, + 1, + null, + ], [ -2299.6141712553544, 0.004175, diff --git a/tests/data/Calculation/Financial/CUMPRINC.php b/tests/data/Calculation/Financial/CUMPRINC.php index 2e623223..e14d5adc 100644 --- a/tests/data/Calculation/Financial/CUMPRINC.php +++ b/tests/data/Calculation/Financial/CUMPRINC.php @@ -21,6 +21,15 @@ return [ 1, 0, ], + [ + -68.278271180977001, + 0.0075, + 360, + 125000, + 1, + 1, + null, + ], [ -9025.875084814226, 0.004175, diff --git a/tests/data/Calculation/Financial/DISC.php b/tests/data/Calculation/Financial/DISC.php index d77b0a81..f33ed21b 100644 --- a/tests/data/Calculation/Financial/DISC.php +++ b/tests/data/Calculation/Financial/DISC.php @@ -18,6 +18,14 @@ return [ 95, 100, ], + [ + 0.01, + '2010-04-01', + '2015-03-31', + 95, + 100, + null, + ], [ '#NUM!', '2010-04-01', diff --git a/tests/data/Calculation/Financial/DaysPerYear.php b/tests/data/Calculation/Financial/DaysPerYear.php index f9ca1c1d..d8adb1c5 100644 --- a/tests/data/Calculation/Financial/DaysPerYear.php +++ b/tests/data/Calculation/Financial/DaysPerYear.php @@ -1,15 +1,15 @@ Date: Tue, 13 Apr 2021 10:11:59 +0900 Subject: [PATCH 181/187] BREAKING `Worksheet::getCell()` cannot return null anymore `Worksheet::getCell()` used to optionnaly return null if passed a second argument. This second argument was removed entirely and the method always returns a Cell (possibly creating it if needed). This make the API more predictable and easier to do static analysis with tools such as PHPStan. If you relied on that second parameter, you should instead use the `Worksheet::cellExists()` before calling `getCell()`. --- phpstan-baseline.neon | 1964 +---------------- .../Calculation/Calculation.php | 4 +- src/PhpSpreadsheet/Worksheet/Worksheet.php | 126 +- .../Worksheet/WorksheetNamedRangesTest.php | 4 +- 4 files changed, 81 insertions(+), 2017 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4566305f..1bad9d03 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -235,11 +235,6 @@ parameters: count: 4 path: src/PhpSpreadsheet/Calculation/Calculation.php - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: src/PhpSpreadsheet/Calculation/Calculation.php - - message: "#^Parameter \\#2 \\$pSheet of static method PhpOffice\\\\PhpSpreadsheet\\\\DefinedName\\:\\:resolveName\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet, PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null given\\.$#" count: 1 @@ -1020,11 +1015,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Functions.php - - - message: "#^Cannot call method isFormula\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Functions.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Internal\\\\MakeMatrix\\:\\:make\\(\\) has parameter \\$args with no typehint specified\\.$#" count: 1 @@ -1070,16 +1060,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - message: "#^Cannot call method isFormula\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/LookupRef.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\LookupRef\\\\Address\\:\\:sheetName\\(\\) has no return typehint specified\\.$#" count: 1 @@ -3395,11 +3375,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Csv.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Csv.php - - message: "#^Parameter \\#2 \\$newvalue of function ini_set expects string, string\\|false given\\.$#" count: 1 @@ -3495,11 +3470,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Offset 'No' does not exist on SimpleXMLElement\\|null\\.$#" count: 2 @@ -3675,11 +3645,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Html.php - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Html.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Html\\:\\:\\$h1Etc has no typehint specified\\.$#" count: 1 @@ -3755,21 +3720,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Ods.php - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Reader/Ods.php - - - - message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods.php - - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Ods.php - - message: "#^Parameter \\#1 \\$settings of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Ods\\:\\:lookForActiveSheet\\(\\) expects DOMElement, DOMElement\\|null given\\.$#" count: 1 @@ -3945,16 +3895,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Slk.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - - - message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Slk.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Slk\\:\\:\\$styleSettingsFont has no typehint specified\\.$#" count: 1 @@ -4065,11 +4005,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 12 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Negated boolean expression is always false\\.$#" count: 1 @@ -4230,16 +4165,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 9 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xls\\:\\:includeCellRangeFiltered\\(\\) has no return typehint specified\\.$#" count: 1 @@ -4250,16 +4175,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xls.php - - - message: "#^Cannot call method getHyperLink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - - - message: "#^Cannot call method getDataValidation\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xls.php - - message: "#^Parameter \\#1 \\$value of method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\DataValidation\\:\\:setType\\(\\) expects string, int\\|string given\\.$#" count: 1 @@ -4560,31 +4475,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx.php - - - message: "#^Cannot call method setFormulaAttributes\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - - - message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - - - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xlsx.php - - message: "#^Parameter \\#1 \\$relsWorksheet of method PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\Hyperlinks\\:\\:readHyperlinks\\(\\) expects SimpleXMLElement, SimpleXMLElement\\|false given\\.$#" count: 1 @@ -5250,11 +5140,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: src/PhpSpreadsheet/Reader/Xlsx/Hyperlinks.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Reader\\\\Xlsx\\\\PageSetup\\:\\:\\$worksheet has no typehint specified\\.$#" count: 1 @@ -5550,21 +5435,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Xml.php - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - - - message: "#^Cannot call method setCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Reader/Xml.php - - message: "#^Cannot call method setRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 1 @@ -5670,46 +5540,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/ReferenceHelper.php - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/ReferenceHelper.php - - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: src/PhpSpreadsheet/ReferenceHelper.php - - - - message: "#^Cannot call method getColumn\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: src/PhpSpreadsheet/ReferenceHelper.php - - - message: "#^Cannot call method getRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/ReferenceHelper.php - - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: src/PhpSpreadsheet/ReferenceHelper.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/ReferenceHelper.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: src/PhpSpreadsheet/ReferenceHelper.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: src/PhpSpreadsheet/ReferenceHelper.php - - message: "#^Parameter \\#1 \\$columnIndex of static method PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Coordinate\\:\\:stringFromColumnIndex\\(\\) expects int, float\\|int given\\.$#" count: 1 @@ -6610,16 +6445,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Spreadsheet.php - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: src/PhpSpreadsheet/Spreadsheet.php - - - - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: src/PhpSpreadsheet/Spreadsheet.php - - message: "#^Cannot call method getTitle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 1 @@ -7125,11 +6950,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Protection.php - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: src/PhpSpreadsheet/Style/Style.php - - message: "#^Call to an undefined method PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\|PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Style\\:\\:getCellXfByIndex\\(\\)\\.$#" count: 1 @@ -7160,6 +6980,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Style/Style.php + - + message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 2 + path: src/PhpSpreadsheet/Style/Style.php + - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -7305,11 +7130,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Worksheet/AutoFilter.php - - message: "#^Left side of && is always true\\.$#" count: 1 @@ -7562,36 +7382,21 @@ parameters: - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Cannot call method getCell\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Parameter \\#2 \\$start of function substr expects int, int\\<0, max\\>\\|false given\\.$#" - count: 3 - path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - - - message: "#^Parameter \\#1 \\$pRow of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getRowDimension\\(\\) expects int, string given\\.$#" count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Cannot call method cellExists\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" + message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + count: 1 + path: src/PhpSpreadsheet/Worksheet/Worksheet.php + + - + message: "#^Parameter \\#2 \\$start of function substr expects int, int\\<0, max\\>\\|false given\\.$#" count: 2 path: src/PhpSpreadsheet/Worksheet/Worksheet.php - - message: "#^Cannot call method setXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" + message: "#^Parameter \\#1 \\$pRow of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\:\\:getRowDimension\\(\\) expects int, string given\\.$#" count: 1 path: src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -8040,11 +7845,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Html\\:\\:calculateSpansOmitRows\\(\\) has parameter \\$candidateSpannedRow with no typehint specified\\.$#" count: 1 @@ -8155,11 +7955,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Pdf/Tcpdf.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls.php - - message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" count: 1 @@ -8375,41 +8170,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Cannot call method getRow\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Cannot call method getColumn\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Cannot call method getHashCode\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" count: 1 path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - message: "#^Cannot call method getDatatype\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: src/PhpSpreadsheet/Writer/Xls/Worksheet.php - - message: "#^Parameter \\#4 \\$isError of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xls\\\\Worksheet\\:\\:writeBoolErr\\(\\) expects bool, int given\\.$#" count: 3 @@ -8860,16 +8625,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx/Rels.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: src/PhpSpreadsheet/Writer/Xlsx/StringTable.php - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int\\<0, max\\> given\\.$#" count: 1 @@ -9125,26 +8880,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - - - message: "#^Parameter \\#3 \\$pCell of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Worksheet\\:\\:writeCellFormula\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Worksheet.php - - message: "#^Right side of && is always true\\.$#" count: 1 @@ -9155,1091 +8890,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx/Xlfn.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 9 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 13 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot call method getWorksheet\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/CalculationTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/DefinedNamesCalculationTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/Engine/RangeTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/FormulaAsStringTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateDifTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DateValueTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DayTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/Days360Test.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/DaysTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EDateTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/EoMonthTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/HourTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/IsoWeekNumTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MinuteTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/MonthTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NetworkDaysTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/NowTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/SecondTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TimeValueTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/TodayTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekDayTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WeekNumTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/WorkDayTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 7 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearFracTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/DateTime/YearTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2DecTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2HexTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Bin2OctTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitAndTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitLShiftTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitOrTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitRShiftTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/BitXorTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2BinTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2HexTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Dec2OctTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2BinTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2DecTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Hex2OctTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2BinTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2DecTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Engineering/Oct2HexTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AbsTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcosTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcoshTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcotTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AcothTest.php - - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AllSetupTeardown.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ArabicTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AsinhTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Atan2Test.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/AtanhTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 7 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/BaseTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingMathTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingPreciseTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CeilingTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinATest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CombinTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CosTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CoshTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CotTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CothTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CscTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/CschTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/DegreesTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/EvenTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ExpTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactDoubleTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FactTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorMathTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorPreciseTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/FloorTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/GcdTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/IntTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LcmTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LnTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/Log10Test.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/LogTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 9 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MRoundTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MdeTermTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ModTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MultinomialTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/OddTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/PowerTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/ProductTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/QuotientTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RadiansTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandBetweenTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RandTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RomanTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundDownTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/RoundUpTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SecTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SechTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SeriesSumTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SignTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SinhTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtPiTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SqrtTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php - - message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 1 @@ -10250,171 +8905,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumIfTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumProductTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumSqTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2MY2Test.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumX2PY2Test.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SumXMY2Test.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TanhTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/TruncTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/ModeTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/Functions/TextData/ReptTest.php - - message: "#^Cannot call method setAutoSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Calculation/XlfnFunctionsTest.php - - - - message: "#^Cannot call method setValueExplicit\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Cell/CellTest.php - - - - message: "#^Cannot call method hasValidValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 9 - path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php - - - - message: "#^Cannot call method getDataValidation\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 8 - path: tests/PhpSpreadsheetTests/Cell/DataValidatorTest.php - - - - message: "#^Parameter \\#2 \\$cell of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:add\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertSame\\(\\) with arguments PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, null and 'should get exact…' will always evaluate to false\\.$#" count: 1 @@ -10430,36 +8925,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - - message: "#^Parameter \\#1 \\$cell of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:update\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell, PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null given\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - message: "#^Parameter \\#1 \\$row of method PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Cells\\:\\:getHighestColumn\\(\\) expects string\\|null, int given\\.$#" count: 3 path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Collection/CellsTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 14 - path: tests/PhpSpreadsheetTests/DefinedNameTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/DefinedNameTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/ActiveSheetTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Functional\\\\ColumnWidthTest\\:\\:testReadColumnWidth\\(\\) has parameter \\$format with no typehint specified\\.$#" count: 1 @@ -10480,21 +8950,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/CommentsTest.php - - message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:addCondition\\(\\) expects string, float given\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Functional/ConditionalStopIfTrueTest.php - - message: "#^Cannot call method setAutoSize\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 1 @@ -10525,26 +8985,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/DrawingImageHyperlinkTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/EnclosureTest.php - - message: "#^Cannot call method getPageSetup\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 5 path: tests/PhpSpreadsheetTests/Functional/PrintAreaTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Functional/ReadBlankCellsTest.php - - message: "#^Cannot access offset 'size' on array\\(0 \\=\\> int, 1 \\=\\> int, 2 \\=\\> int, 3 \\=\\> int, 4 \\=\\> int, 5 \\=\\> int, 6 \\=\\> int, 7 \\=\\> int, \\.\\.\\.\\)\\|false\\.$#" count: 2 @@ -10560,26 +9005,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Functional/StreamTest.php - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - - - message: "#^Cannot call method getOldCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Functional/TypeAttributePreservationTest.php - - message: "#^Parameter \\#1 \\$expected of static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) expects class\\-string\\, string given\\.$#" count: 3 @@ -10625,76 +9050,21 @@ parameters: count: 3 path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Reader/CsvContiguousTest.php - - message: "#^Call to static method PHPUnit\\\\Framework\\\\Assert\\:\\:assertNull\\(\\) with string will always evaluate to false\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 13 - path: tests/PhpSpreadsheetTests/Reader/CsvTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 10 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 67 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php - - - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php - - message: "#^Cannot call method getVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/Gnumeric/GnumericLoadTest.php - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlBorderTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 7 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlLoadStringTest.php - - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 50 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php - - message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTagsTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 16 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php - - message: "#^Cannot call method getWidth\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 2 @@ -10705,36 +9075,6 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 16 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 14 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Ods/OdsTest.php - - message: "#^Unreachable statement \\- code above always terminates\\.$#" count: 1 @@ -10755,31 +9095,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Security/XmlScannerTest.php - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 52 - path: tests/PhpSpreadsheetTests/Reader/SlkTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 7 - path: tests/PhpSpreadsheetTests/Reader/SlkTest.php - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/SlkTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/XlsTest.php - - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Reader/XlsTest.php - - message: "#^Cannot call method getCoordinate\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" count: 1 @@ -10835,11 +9155,6 @@ parameters: count: 5 path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php - - message: "#^Cannot call method getConditionalFormattingRuleExt\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\ConditionalFormatting\\\\ConditionalDataBar\\|null\\.$#" count: 8 @@ -10850,11 +9165,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Xlsx/ConditionalFormattingDataBarXlsxTest.php - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Reader/Xlsx/NamedRangeTest.php - - message: "#^Cannot call method getRowHeight\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowDimension\\|null\\.$#" count: 1 @@ -10875,51 +9185,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - - message: "#^Cannot call method hasDataValidation\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\XlsxTest\\:\\:testStripsWhiteSpaceFromStyleString\\(\\) has parameter \\$string with no typehint specified\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Reader/XlsxTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 11 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php - - - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php - - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlLoadTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlOddTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 70 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlStylesTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Reader\\\\Xml\\\\XmlTest\\:\\:testInvalidSimpleXML\\(\\) has parameter \\$filename with no typehint specified\\.$#" count: 1 @@ -10930,31 +9200,11 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - - - message: "#^Cannot call method getHyperlink\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Reader/Xml/XmlTest.php - - message: "#^Parameter \\#1 \\$timeZone of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Date\\:\\:setDefaultTimezone\\(\\) expects DateTimeZone\\|string, DateTimeZone\\|null given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Shared/DateTest.php - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\StringHelper\\:\\:setCurrencyCode\\(\\) expects string, null given\\.$#" count: 1 @@ -10985,41 +9235,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/SpreadsheetTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/SpreadsheetTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/SpreadsheetTest.php - - - - message: "#^Cannot call method getXfIndex\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/SpreadsheetTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/SpreadsheetTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 9 - path: tests/PhpSpreadsheetTests/Style/AlignmentTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 29 - path: tests/PhpSpreadsheetTests/Style/AlignmentTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 65 - path: tests/PhpSpreadsheetTests/Style/BorderTest.php - - message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Conditional\\:\\:addCondition\\(\\) expects string, float given\\.$#" count: 2 @@ -11030,51 +9245,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Style/ConditionalTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 10 - path: tests/PhpSpreadsheetTests/Style/ExportArrayTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 10 - path: tests/PhpSpreadsheetTests/Style/ExportArrayTest.php - - - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Style/ExportArrayTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/FontTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Style/FontTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 6 - path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php - - - - message: "#^Cannot call method getFormattedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 3 - path: tests/PhpSpreadsheetTests/Style/NumberFormatBuiltinTest.php - - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 5 - path: tests/PhpSpreadsheetTests/Style/StyleTest.php - - message: "#^Parameter \\#1 \\$pValue of method PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\AutoFilter\\\\Column\\\\Rule\\:\\:setValue\\(\\) expects array\\\\|string, int given\\.$#" count: 1 @@ -11095,11 +9265,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Worksheet/AutoFilterTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Worksheet/ColumnCellIterator2Test.php - - message: "#^Parameter \\#1 \\$im of function imagecolorallocate expects resource, resource\\|false given\\.$#" count: 1 @@ -11120,11 +9285,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Worksheet/DrawingTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Worksheet/RowCellIterator2Test.php - - message: "#^Parameter \\#2 \\$rowIndex of class PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\RowCellIterator constructor expects int, string given\\.$#" count: 1 @@ -11135,26 +9295,6 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Worksheet/WorksheetTest.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Csv\\\\CsvEnclosureTest\\:\\:\\$cellValues has no typehint specified\\.$#" count: 1 @@ -11165,16 +9305,6 @@ parameters: count: 4 path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 11 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvEnclosureTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Csv/CsvWriteTest.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheetTests\\\\Writer\\\\Html\\\\CallbackTest\\:\\:yellowBody\\(\\) should return string but returns string\\|null\\.$#" count: 1 @@ -11200,36 +9330,16 @@ parameters: count: 3 path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php - - - message: "#^Cannot call method getStyle\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Html/GridlinesTest.php - - message: "#^Cannot call method setBold\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null\\.$#" count: 3 path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlCommentsTest.php - - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Html/HtmlNumberFormatTest.php - - message: "#^Parameter \\#1 \\$directory of function chdir expects string, string\\|false given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/ImagesRootTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Writer/Html/InvalidFileNameTest.php - - message: "#^Cannot call method setVisible\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\ColumnDimension\\|null\\.$#" count: 2 @@ -11245,41 +9355,16 @@ parameters: count: 1 path: tests/PhpSpreadsheetTests/Writer/Html/VisibilityTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Html/XssVulnerabilityTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Writer/Xls/FormulaErrTest.php - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/FloatsRetainedTest.php - - message: "#^Parameter \\#2 \\$locale of function setlocale expects string\\|null, string\\|false given\\.$#" count: 1 path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest.php - - message: "#^Parameter \\#2 \\$subject of function preg_match expects string, string\\|false given\\.$#" count: 1 @@ -11290,31 +9375,11 @@ parameters: count: 2 path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 1 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - - message: "#^Cannot call method getCalculatedValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - - - message: "#^Cannot call method getDataType\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/StartsWithHashTest.php - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" count: 2 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - message: "#^Cannot call method setValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 2 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - message: "#^Cannot call method getDrawingCollection\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" count: 4 @@ -11325,11 +9390,6 @@ parameters: count: 4 path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - - message: "#^Cannot call method getValue\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Cell\\\\Cell\\|null\\.$#" - count: 4 - path: tests/PhpSpreadsheetTests/Writer/Xlsx/UnparsedDataCloneTest.php - - message: "#^Parameter \\#1 \\$options of static method PhpOffice\\\\PhpSpreadsheet\\\\Settings\\:\\:setLibXmlLoaderOptions\\(\\) expects int, null given\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index 32586b4c..dfaa566a 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -5334,9 +5334,7 @@ class Calculation $recursiveCalculationCell = ($definedNameWorksheet !== null && $definedNameWorksheet !== $pCellWorksheet) ? $definedNameWorksheet->getCell('A1') : $pCell; - $recursiveCalculationCellAddress = $recursiveCalculationCell !== null - ? $recursiveCalculationCell->getCoordinate() - : null; + $recursiveCalculationCellAddress = $recursiveCalculationCell->getCoordinate(); // Adjust relative references in ranges and formulae so that we execute the calculation for the correct rows and columns $definedNameValue = self::$referenceHelper->updateFormulaReferencesAnyWorksheet( diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 02d7692b..4e68a17f 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -730,7 +730,7 @@ class Worksheet implements IComparable // loop through all cells in the worksheet foreach ($this->getCoordinates(false) as $coordinate) { - $cell = $this->getCell($coordinate, false); + $cell = $this->getCellOrNull($coordinate); if ($cell !== null && isset($autoSizes[$this->cellCollection->getCurrentColumn()])) { //Determine if cell is in merge range $isMerged = isset($isMergeCell[$this->cellCollection->getCurrentCoordinate()]); @@ -1168,52 +1168,86 @@ class Worksheet implements IComparable /** * Get cell at a specific coordinate. * - * @param string $pCoordinate Coordinate of the cell, eg: 'A1' - * @param bool $createIfNotExists Flag indicating whether a new cell should be created if it doesn't - * already exist, or a null should be returned instead + * @param string $coordinate Coordinate of the cell, eg: 'A1' * - * @return null|Cell Cell that was found/created or null + * @return Cell Cell that was found or created */ - public function getCell($pCoordinate, $createIfNotExists = true) + public function getCell(string $coordinate): Cell { - // Uppercase coordinate - $pCoordinateUpper = strtoupper($pCoordinate); + /** @var Worksheet $sheet */ + [$sheet, $finalCoordinate] = $this->getWorksheetAndCoordinate($coordinate); + $cell = $sheet->cellCollection->get($finalCoordinate); - // Check cell collection - if ($this->cellCollection->has($pCoordinateUpper)) { - return $this->cellCollection->get($pCoordinateUpper); - } + return $cell ?? $sheet->createNewCell($finalCoordinate); + } + + /** + * Get the correct Worksheet and coordinate from a coordinate that may + * contains reference to another sheet or a named range. + * + * @return array{0: Worksheet, 1: string} + */ + private function getWorksheetAndCoordinate(string $pCoordinate): array + { + $sheet = null; + $finalCoordinate = null; // Worksheet reference? if (strpos($pCoordinate, '!') !== false) { $worksheetReference = self::extractSheetTitle($pCoordinate, true); - return $this->parent->getSheetByName($worksheetReference[0]) - ->getCell(strtoupper($worksheetReference[1]), $createIfNotExists); - } + $sheet = $this->parent->getSheetByName($worksheetReference[0]); + $finalCoordinate = strtoupper($worksheetReference[1]); - // Named range? - if ( - (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate, $matches)) && - (preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate, $matches)) + if (!$sheet) { + throw new Exception('Sheet not found for name: ' . $worksheetReference[0]); + } + } elseif ( + !preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate) && + preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate) ) { + // Named range? $namedRange = $this->validateNamedRange($pCoordinate, true); if ($namedRange !== null) { - $cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); - $cellCoordinate = str_replace('$', '', $cellCoordinate); + $sheet = $namedRange->getWorksheet(); + if (!$sheet) { + throw new Exception('Sheet not found for named range: ' . $namedRange->getName()); + } - return $namedRange->getWorksheet()->getCell($cellCoordinate, $createIfNotExists); + $cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); + $finalCoordinate = str_replace('$', '', $cellCoordinate); } } - if (Coordinate::coordinateIsRange($pCoordinate)) { - throw new Exception('Cell coordinate can not be a range of cells.'); - } elseif (strpos($pCoordinate, '$') !== false) { + if (!$sheet || !$finalCoordinate) { + $sheet = $this; + $finalCoordinate = strtoupper($pCoordinate); + } + + if (Coordinate::coordinateIsRange($finalCoordinate)) { + throw new Exception('Cell coordinate string can not be a range of cells.'); + } elseif (strpos($finalCoordinate, '$') !== false) { throw new Exception('Cell coordinate must not be absolute.'); } - // Create new cell object, if required - return $createIfNotExists ? $this->createNewCell($pCoordinateUpper) : null; + return [$sheet, $finalCoordinate]; + } + + /** + * Get an existing cell at a specific coordinate, or null. + * + * @param string $coordinate Coordinate of the cell, eg: 'A1' + * + * @return null|Cell Cell that was found or null + */ + private function getCellOrNull($coordinate): ?Cell + { + // Check cell collection + if ($this->cellCollection->has($coordinate)) { + return $this->cellCollection->get($coordinate); + } + + return null; } /** @@ -1281,44 +1315,16 @@ class Worksheet implements IComparable /** * Does the cell at a specific coordinate exist? * - * @param string $pCoordinate Coordinate of the cell eg: 'A1' + * @param string $coordinate Coordinate of the cell eg: 'A1' * * @return bool */ - public function cellExists($pCoordinate) + public function cellExists($coordinate) { - // Worksheet reference? - if (strpos($pCoordinate, '!') !== false) { - $worksheetReference = self::extractSheetTitle($pCoordinate, true); + /** @var Worksheet $sheet */ + [$sheet, $finalCoordinate] = $this->getWorksheetAndCoordinate($coordinate); - return $this->parent->getSheetByName($worksheetReference[0])->cellExists(strtoupper($worksheetReference[1])); - } - - // Named range? - if ( - (!preg_match('/^' . Calculation::CALCULATION_REGEXP_CELLREF . '$/i', $pCoordinate, $matches)) && - (preg_match('/^' . Calculation::CALCULATION_REGEXP_DEFINEDNAME . '$/i', $pCoordinate, $matches)) - ) { - $namedRange = $this->validateNamedRange($pCoordinate, true); - if ($namedRange !== null) { - $cellCoordinate = ltrim(substr($namedRange->getValue(), strrpos($namedRange->getValue(), '!')), '!'); - $cellCoordinate = str_replace('$', '', $cellCoordinate); - - return $namedRange->getWorksheet()->cellExists($cellCoordinate); - } - } - - // Uppercase coordinate - $pCoordinate = strtoupper($pCoordinate); - - if (Coordinate::coordinateIsRange($pCoordinate)) { - throw new Exception('Cell coordinate can not be a range of cells.'); - } elseif (strpos($pCoordinate, '$') !== false) { - throw new Exception('Cell coordinate must not be absolute.'); - } - - // Cell exists? - return $this->cellCollection->has($pCoordinate); + return $sheet->cellCollection->has($finalCoordinate); } /** diff --git a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php index 24775e3b..1560f1ed 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/WorksheetNamedRangesTest.php @@ -55,7 +55,7 @@ class WorksheetNamedRangesTest extends TestCase $namedRange = 'Range1'; $this->expectException(Exception::class); - $this->expectExceptionMessage('Cell coordinate can not be a range of cells'); + $this->expectExceptionMessage('Cell coordinate string can not be a range of cells'); $worksheet = $this->spreadsheet->getActiveSheet(); $worksheet->cellExists($namedRange); @@ -118,7 +118,7 @@ class WorksheetNamedRangesTest extends TestCase $namedCell = 'Range1'; $this->expectException(Exception::class); - $this->expectExceptionMessage('Cell coordinate can not be a range of cells'); + $this->expectExceptionMessage('Cell coordinate string can not be a range of cells'); $worksheet = $this->spreadsheet->getActiveSheet(); $worksheet->getCell($namedCell); From 33ec70668b256fc2e6417a250ba789a68e393e6e Mon Sep 17 00:00:00 2001 From: Adrien Crivelli Date: Tue, 13 Apr 2021 11:33:37 +0900 Subject: [PATCH 182/187] Shortcut for increased performance for the vast majority of simple cases --- src/PhpSpreadsheet/Worksheet/Worksheet.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 4e68a17f..2ecd210c 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -1174,6 +1174,14 @@ class Worksheet implements IComparable */ public function getCell(string $coordinate): Cell { + // Shortcut for increased performance for the vast majority of simple cases + if ($this->cellCollection->has($coordinate)) { + /** @var Cell $cell */ + $cell = $this->cellCollection->get($coordinate); + + return $cell; + } + /** @var Worksheet $sheet */ [$sheet, $finalCoordinate] = $this->getWorksheetAndCoordinate($coordinate); $cell = $sheet->cellCollection->get($finalCoordinate); From ddd07ee504e76d366b242305b3a60378add8fe90 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 13 Apr 2021 16:56:21 +0200 Subject: [PATCH 183/187] =?UTF-8?q?Use=20validation=20classes=20rather=20t?= =?UTF-8?q?han=20traits=20for=20Statistical=20functions,=20=E2=80=A6=20(#1?= =?UTF-8?q?999)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use validation classes rather than traits for Statistical functions, and some verification of nullable arguments * Eliminate more of the issues resolved in phpstan baseline --- phpstan-baseline.neon | 490 ------------------ .../Statistical/BaseValidations.php | 27 - .../Calculation/Statistical/Confidence.php | 8 +- .../Distributions/BaseValidations.php | 47 -- .../Statistical/Distributions/Beta.php | 37 +- .../Statistical/Distributions/Binomial.php | 30 +- .../Statistical/Distributions/ChiSquared.php | 34 +- .../Distributions/DistributionValidations.php | 24 + .../Statistical/Distributions/Exponential.php | 8 +- .../Statistical/Distributions/F.php | 10 +- .../Statistical/Distributions/Fisher.php | 6 +- .../Statistical/Distributions/Gamma.php | 20 +- .../Distributions/HyperGeometric.php | 10 +- .../Statistical/Distributions/LogNormal.php | 22 +- .../Statistical/Distributions/Normal.php | 16 +- .../Statistical/Distributions/Poisson.php | 8 +- .../Statistical/Distributions/StudentT.php | 12 +- .../Statistical/Distributions/Weibull.php | 10 +- .../Calculation/Statistical/Percentiles.php | 14 +- .../Calculation/Statistical/Permutations.php | 10 +- .../Statistical/StatisticalValidations.php | 45 ++ .../Calculation/Statistical/Trends.php | 4 +- .../data/Calculation/Statistical/BETADIST.php | 4 + .../data/Calculation/Statistical/BETAINV.php | 4 + .../Statistical/BINOMDISTRANGE.php | 4 + tests/data/Calculation/Statistical/ZTEST.php | 6 + 26 files changed, 207 insertions(+), 703 deletions(-) delete mode 100644 src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php delete mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/Distributions/DistributionValidations.php create mode 100644 src/PhpSpreadsheet/Calculation/Statistical/StatisticalValidations.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1bad9d03..4e5b7385 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1500,36 +1500,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Averages.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Confidence\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Confidence.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Confidence\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Confidence.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Confidence.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Percentiles\\:\\:percentileFilterValues\\(\\) has no return typehint specified\\.$#" count: 1 @@ -1540,36 +1510,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Permutations\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Permutations\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Permutations.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Trends.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Trends\\:\\:checkTrendArrays\\(\\) has parameter \\$array1 with no typehint specified\\.$#" count: 1 @@ -1625,41 +1565,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Conditional.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:calculateInverse\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Beta\\:\\:\\$logBetaCacheP has no typehint specified\\.$#" count: 1 @@ -1675,106 +1580,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Binomial\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Binary operation \"\\*\" between int\\|string and \\(float\\|int\\) results in an error\\.$#" - count: 3 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - message: "#^Binary operation \"\\-\" between 1 and float\\|string results in an error\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:test\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:test\\(\\) has parameter \\$actual with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:test\\(\\) has parameter \\$expected with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:inverseLeftTailCalculation\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:inverseLeftTailCalculation\\(\\) has parameter \\$degrees with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:inverseLeftTailCalculation\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\ChiSquared\\:\\:pchisq\\(\\) has no return typehint specified\\.$#" count: 1 @@ -1835,221 +1645,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Exponential\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\F\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Fisher\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Gamma\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\HyperGeometric\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - message: "#^Binary operation \"\\*\" between int\\|string and int\\|string results in an error\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\LogNormal\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:inverseNcdf\\(\\) has no return typehint specified\\.$#" count: 1 @@ -2060,96 +1660,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Poisson\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\StudentT\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateBool\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateProbability\\(\\) has no return typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Weibull\\:\\:validateProbability\\(\\) has parameter \\$probability with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\GammaBase\\:\\:calculateDistribution\\(\\) has no return typehint specified\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php deleted file mode 100644 index 1dbe4212..00000000 --- a/src/PhpSpreadsheet/Calculation/Statistical/BaseValidations.php +++ /dev/null @@ -1,27 +0,0 @@ -getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php deleted file mode 100644 index a2e0b042..00000000 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/BaseValidations.php +++ /dev/null @@ -1,47 +0,0 @@ - 1.0) { - throw new Exception(Functions::NAN()); - } - - return $probability; - } -} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php index 95446c45..63e6eb4d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Beta.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Beta { - use BaseValidations; - private const MAX_ITERATIONS = 256; private const LOG_GAMMA_X_MAX_VALUE = 2.55e305; @@ -28,20 +26,20 @@ class Beta * * @return float|string */ - public static function distribution($value, $alpha, $beta, $rMin = 0, $rMax = 1) + public static function distribution($value, $alpha, $beta, $rMin = 0.0, $rMax = 1.0) { $value = Functions::flattenSingleValue($value); $alpha = Functions::flattenSingleValue($alpha); $beta = Functions::flattenSingleValue($beta); - $rMin = Functions::flattenSingleValue($rMin); - $rMax = Functions::flattenSingleValue($rMax); + $rMin = ($rMin === null) ? 0.0 : Functions::flattenSingleValue($rMin); + $rMax = ($rMax === null) ? 1.0 : Functions::flattenSingleValue($rMax); try { - $value = self::validateFloat($value); - $alpha = self::validateFloat($alpha); - $beta = self::validateFloat($beta); - $rMax = self::validateFloat($rMax); - $rMin = self::validateFloat($rMin); + $value = DistributionValidations::validateFloat($value); + $alpha = DistributionValidations::validateFloat($alpha); + $beta = DistributionValidations::validateFloat($beta); + $rMax = DistributionValidations::validateFloat($rMax); + $rMin = DistributionValidations::validateFloat($rMin); } catch (Exception $e) { return $e->getMessage(); } @@ -74,20 +72,20 @@ class Beta * * @return float|string */ - public static function inverse($probability, $alpha, $beta, $rMin = 0, $rMax = 1) + public static function inverse($probability, $alpha, $beta, $rMin = 0.0, $rMax = 1.0) { $probability = Functions::flattenSingleValue($probability); $alpha = Functions::flattenSingleValue($alpha); $beta = Functions::flattenSingleValue($beta); - $rMin = Functions::flattenSingleValue($rMin); - $rMax = Functions::flattenSingleValue($rMax); + $rMin = ($rMin === null) ? 0.0 : Functions::flattenSingleValue($rMin); + $rMax = ($rMax === null) ? 1.0 : Functions::flattenSingleValue($rMax); try { - $probability = self::validateProbability($probability); - $alpha = self::validateFloat($alpha); - $beta = self::validateFloat($beta); - $rMax = self::validateFloat($rMax); - $rMin = self::validateFloat($rMin); + $probability = DistributionValidations::validateProbability($probability); + $alpha = DistributionValidations::validateFloat($alpha); + $beta = DistributionValidations::validateFloat($beta); + $rMax = DistributionValidations::validateFloat($rMax); + $rMin = DistributionValidations::validateFloat($rMin); } catch (Exception $e) { return $e->getMessage(); } @@ -104,6 +102,9 @@ class Beta return self::calculateInverse($probability, $alpha, $beta, $rMin, $rMax); } + /** + * @return float|string + */ private static function calculateInverse(float $probability, float $alpha, float $beta, float $rMin, float $rMax) { $a = 0; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php index acdda8d3..ffc82afa 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php @@ -8,8 +8,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Binomial { - use BaseValidations; - /** * BINOMDIST. * @@ -33,10 +31,10 @@ class Binomial $probability = Functions::flattenSingleValue($probability); try { - $value = self::validateInt($value); - $trials = self::validateInt($trials); - $probability = self::validateProbability($probability); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateInt($value); + $trials = DistributionValidations::validateInt($trials); + $probability = DistributionValidations::validateProbability($probability); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } @@ -74,10 +72,10 @@ class Binomial $limit = ($limit === null) ? $successes : Functions::flattenSingleValue($limit); try { - $trials = self::validateInt($trials); - $probability = self::validateProbability($probability); - $successes = self::validateInt($successes); - $limit = self::validateInt($limit); + $trials = DistributionValidations::validateInt($trials); + $probability = DistributionValidations::validateProbability($probability); + $successes = DistributionValidations::validateInt($successes); + $limit = DistributionValidations::validateInt($limit); } catch (Exception $e) { return $e->getMessage(); } @@ -122,9 +120,9 @@ class Binomial $probability = Functions::flattenSingleValue($probability); try { - $failures = self::validateInt($failures); - $successes = self::validateInt($successes); - $probability = self::validateProbability($probability); + $failures = DistributionValidations::validateInt($failures); + $successes = DistributionValidations::validateInt($successes); + $probability = DistributionValidations::validateProbability($probability); } catch (Exception $e) { return $e->getMessage(); } @@ -161,9 +159,9 @@ class Binomial $alpha = Functions::flattenSingleValue($alpha); try { - $trials = self::validateInt($trials); - $probability = self::validateProbability($probability); - $alpha = self::validateFloat($alpha); + $trials = DistributionValidations::validateInt($trials); + $probability = DistributionValidations::validateProbability($probability); + $alpha = DistributionValidations::validateFloat($alpha); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php index efc62f83..5165d639 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class ChiSquared { - use BaseValidations; - private const MAX_ITERATIONS = 256; private const EPS = 2.22e-16; @@ -29,8 +27,8 @@ class ChiSquared $degrees = Functions::flattenSingleValue($degrees); try { - $value = self::validateFloat($value); - $degrees = self::validateInt($degrees); + $value = DistributionValidations::validateFloat($value); + $degrees = DistributionValidations::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } @@ -67,9 +65,9 @@ class ChiSquared $cumulative = Functions::flattenSingleValue($cumulative); try { - $value = self::validateFloat($value); - $degrees = self::validateInt($degrees); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $degrees = DistributionValidations::validateInt($degrees); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } @@ -109,8 +107,8 @@ class ChiSquared $degrees = Functions::flattenSingleValue($degrees); try { - $probability = self::validateProbability($probability); - $degrees = self::validateInt($degrees); + $probability = DistributionValidations::validateProbability($probability); + $degrees = DistributionValidations::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } @@ -145,8 +143,8 @@ class ChiSquared $degrees = Functions::flattenSingleValue($degrees); try { - $probability = self::validateProbability($probability); - $degrees = self::validateInt($degrees); + $probability = DistributionValidations::validateProbability($probability); + $degrees = DistributionValidations::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } @@ -158,6 +156,18 @@ class ChiSquared return self::inverseLeftTailCalculation($probability, $degrees); } + /** + * CHITEST. + * + * Uses the chi-square test to calculate the probability that the differences between two supplied data sets + * (of observed and expected frequencies), are likely to be simply due to sampling error, + * or if they are likely to be real. + * + * @param mixed $actual an array of observed frequencies + * @param mixed $expected an array of expected frequencies + * + * @return float|string + */ public static function test($actual, $expected) { $rows = count($actual); @@ -199,7 +209,7 @@ class ChiSquared return ($columns - 1) * ($rows - 1); } - private static function inverseLeftTailCalculation($probability, $degrees) + private static function inverseLeftTailCalculation(float $probability, int $degrees): float { // bracket the root $min = 0; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/DistributionValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/DistributionValidations.php new file mode 100644 index 00000000..57ef00af --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/DistributionValidations.php @@ -0,0 +1,24 @@ + 1.0) { + throw new Exception(Functions::NAN()); + } + + return $probability; + } +} diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php index 7cf60344..b3fd9460 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Exponential.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Exponential { - use BaseValidations; - /** * EXPONDIST. * @@ -29,9 +27,9 @@ class Exponential $cumulative = Functions::flattenSingleValue($cumulative); try { - $value = self::validateFloat($value); - $lambda = self::validateFloat($lambda); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $lambda = DistributionValidations::validateFloat($lambda); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php index aaf5f0df..54b1950d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/F.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class F { - use BaseValidations; - /** * F.DIST. * @@ -32,10 +30,10 @@ class F $cumulative = Functions::flattenSingleValue($cumulative); try { - $value = self::validateFloat($value); - $u = self::validateInt($u); - $v = self::validateInt($v); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $u = DistributionValidations::validateInt($u); + $v = DistributionValidations::validateInt($v); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php index fd7986b0..923bf02d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Fisher.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Fisher { - use BaseValidations; - /** * FISHER. * @@ -25,7 +23,7 @@ class Fisher $value = Functions::flattenSingleValue($value); try { - self::validateFloat($value); + DistributionValidations::validateFloat($value); } catch (Exception $e) { return $e->getMessage(); } @@ -53,7 +51,7 @@ class Fisher $probability = Functions::flattenSingleValue($probability); try { - self::validateFloat($probability); + DistributionValidations::validateFloat($probability); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php index aed25f19..2c6ed670 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Gamma.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Gamma extends GammaBase { - use BaseValidations; - /** * GAMMA. * @@ -23,7 +21,7 @@ class Gamma extends GammaBase $value = Functions::flattenSingleValue($value); try { - $value = self::validateFloat($value); + $value = DistributionValidations::validateFloat($value); } catch (Exception $e) { return $e->getMessage(); } @@ -54,10 +52,10 @@ class Gamma extends GammaBase $b = Functions::flattenSingleValue($b); try { - $value = self::validateFloat($value); - $a = self::validateFloat($a); - $b = self::validateFloat($b); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $a = DistributionValidations::validateFloat($a); + $b = DistributionValidations::validateFloat($b); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } @@ -87,9 +85,9 @@ class Gamma extends GammaBase $beta = Functions::flattenSingleValue($beta); try { - $probability = self::validateProbability($probability); - $alpha = self::validateFloat($alpha); - $beta = self::validateFloat($beta); + $probability = DistributionValidations::validateProbability($probability); + $alpha = DistributionValidations::validateFloat($alpha); + $beta = DistributionValidations::validateFloat($beta); } catch (Exception $e) { return $e->getMessage(); } @@ -115,7 +113,7 @@ class Gamma extends GammaBase $value = Functions::flattenSingleValue($value); try { - $value = self::validateFloat($value); + $value = DistributionValidations::validateFloat($value); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php index 487e0d46..b74cfc5f 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php @@ -8,8 +8,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class HyperGeometric { - use BaseValidations; - /** * HYPGEOMDIST. * @@ -31,10 +29,10 @@ class HyperGeometric $populationNumber = Functions::flattenSingleValue($populationNumber); try { - $sampleSuccesses = self::validateInt($sampleSuccesses); - $sampleNumber = self::validateInt($sampleNumber); - $populationSuccesses = self::validateInt($populationSuccesses); - $populationNumber = self::validateInt($populationNumber); + $sampleSuccesses = DistributionValidations::validateInt($sampleSuccesses); + $sampleNumber = DistributionValidations::validateInt($sampleNumber); + $populationSuccesses = DistributionValidations::validateInt($populationSuccesses); + $populationNumber = DistributionValidations::validateInt($populationNumber); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php index 79d19ccf..e1523773 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/LogNormal.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class LogNormal { - use BaseValidations; - /** * LOGNORMDIST. * @@ -28,9 +26,9 @@ class LogNormal $stdDev = Functions::flattenSingleValue($stdDev); try { - $value = self::validateFloat($value); - $mean = self::validateFloat($mean); - $stdDev = self::validateFloat($stdDev); + $value = DistributionValidations::validateFloat($value); + $mean = DistributionValidations::validateFloat($mean); + $stdDev = DistributionValidations::validateFloat($stdDev); } catch (Exception $e) { return $e->getMessage(); } @@ -63,10 +61,10 @@ class LogNormal $cumulative = Functions::flattenSingleValue($cumulative); try { - $value = self::validateFloat($value); - $mean = self::validateFloat($mean); - $stdDev = self::validateFloat($stdDev); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $mean = DistributionValidations::validateFloat($mean); + $stdDev = DistributionValidations::validateFloat($stdDev); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } @@ -105,9 +103,9 @@ class LogNormal $stdDev = Functions::flattenSingleValue($stdDev); try { - $probability = self::validateProbability($probability); - $mean = self::validateFloat($mean); - $stdDev = self::validateFloat($stdDev); + $probability = DistributionValidations::validateProbability($probability); + $mean = DistributionValidations::validateFloat($mean); + $stdDev = DistributionValidations::validateFloat($stdDev); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php index b24c0ecf..4d158b8c 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Normal.php @@ -8,8 +8,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Normal { - use BaseValidations; - public const SQRT2PI = 2.5066282746310005024157652848110452530069867406099; /** @@ -33,10 +31,10 @@ class Normal $stdDev = Functions::flattenSingleValue($stdDev); try { - $value = self::validateFloat($value); - $mean = self::validateFloat($mean); - $stdDev = self::validateFloat($stdDev); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $mean = DistributionValidations::validateFloat($mean); + $stdDev = DistributionValidations::validateFloat($stdDev); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } @@ -70,9 +68,9 @@ class Normal $stdDev = Functions::flattenSingleValue($stdDev); try { - $probability = self::validateProbability($probability); - $mean = self::validateFloat($mean); - $stdDev = self::validateFloat($stdDev); + $probability = DistributionValidations::validateProbability($probability); + $mean = DistributionValidations::validateFloat($mean); + $stdDev = DistributionValidations::validateFloat($stdDev); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php index e6d758e0..c25194a7 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Poisson.php @@ -8,8 +8,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Poisson { - use BaseValidations; - /** * POISSON. * @@ -29,9 +27,9 @@ class Poisson $mean = Functions::flattenSingleValue($mean); try { - $value = self::validateFloat($value); - $mean = self::validateFloat($mean); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $mean = DistributionValidations::validateFloat($mean); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php index 79113bad..45d590dd 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/StudentT.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class StudentT { - use BaseValidations; - private const MAX_ITERATIONS = 256; /** @@ -29,9 +27,9 @@ class StudentT $tails = Functions::flattenSingleValue($tails); try { - $value = self::validateFloat($value); - $degrees = self::validateInt($degrees); - $tails = self::validateInt($tails); + $value = DistributionValidations::validateFloat($value); + $degrees = DistributionValidations::validateInt($degrees); + $tails = DistributionValidations::validateInt($tails); } catch (Exception $e) { return $e->getMessage(); } @@ -59,8 +57,8 @@ class StudentT $degrees = Functions::flattenSingleValue($degrees); try { - $probability = self::validateProbability($probability); - $degrees = self::validateInt($degrees); + $probability = DistributionValidations::validateProbability($probability); + $degrees = DistributionValidations::validateInt($degrees); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php index 5c28e69a..ecec8a85 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Weibull.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Weibull { - use BaseValidations; - /** * WEIBULL. * @@ -30,10 +28,10 @@ class Weibull $cumulative = Functions::flattenSingleValue($cumulative); try { - $value = self::validateFloat($value); - $alpha = self::validateFloat($alpha); - $beta = self::validateFloat($beta); - $cumulative = self::validateBool($cumulative); + $value = DistributionValidations::validateFloat($value); + $alpha = DistributionValidations::validateFloat($alpha); + $beta = DistributionValidations::validateFloat($beta); + $cumulative = DistributionValidations::validateBool($cumulative); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php b/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php index 1f454247..16cb06e8 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Percentiles.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Percentiles { - use BaseValidations; - public const RANK_SORT_DESCENDING = 0; public const RANK_SORT_ASCENDING = 1; @@ -33,7 +31,7 @@ class Percentiles $entry = array_pop($aArgs); try { - $entry = self::validateFloat($entry); + $entry = StatisticalValidations::validateFloat($entry); } catch (Exception $e) { return $e->getMessage(); } @@ -82,8 +80,8 @@ class Percentiles $significance = ($significance === null) ? 3 : Functions::flattenSingleValue($significance); try { - $value = self::validateFloat($value); - $significance = self::validateInt($significance); + $value = StatisticalValidations::validateFloat($value); + $significance = StatisticalValidations::validateInt($significance); } catch (Exception $e) { return $e->getMessage(); } @@ -132,7 +130,7 @@ class Percentiles $entry = array_pop($aArgs); try { - $entry = self::validateFloat($entry); + $entry = StatisticalValidations::validateFloat($entry); } catch (Exception $e) { return $e->getMessage(); } @@ -164,8 +162,8 @@ class Percentiles $order = ($order === null) ? self::RANK_SORT_DESCENDING : Functions::flattenSingleValue($order); try { - $value = self::validateFloat($value); - $order = self::validateInt($order); + $value = StatisticalValidations::validateFloat($value); + $order = StatisticalValidations::validateInt($order); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php index c381d718..6330d39f 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Permutations.php @@ -8,8 +8,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; class Permutations { - use BaseValidations; - /** * PERMUT. * @@ -30,8 +28,8 @@ class Permutations $numInSet = Functions::flattenSingleValue($numInSet); try { - $numObjs = self::validateInt($numObjs); - $numInSet = self::validateInt($numInSet); + $numObjs = StatisticalValidations::validateInt($numObjs); + $numInSet = StatisticalValidations::validateInt($numInSet); } catch (Exception $e) { return $e->getMessage(); } @@ -60,8 +58,8 @@ class Permutations $numInSet = Functions::flattenSingleValue($numInSet); try { - $numObjs = self::validateInt($numObjs); - $numInSet = self::validateInt($numInSet); + $numObjs = StatisticalValidations::validateInt($numObjs); + $numInSet = StatisticalValidations::validateInt($numInSet); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/StatisticalValidations.php b/src/PhpSpreadsheet/Calculation/Statistical/StatisticalValidations.php new file mode 100644 index 00000000..5b315da4 --- /dev/null +++ b/src/PhpSpreadsheet/Calculation/Statistical/StatisticalValidations.php @@ -0,0 +1,45 @@ + $value) { @@ -120,7 +118,7 @@ class Trends $xValue = Functions::flattenSingleValue($xValue); try { - $xValue = self::validateFloat($xValue); + $xValue = StatisticalValidations::validateFloat($xValue); self::checkTrendArrays($yValues, $xValues); self::validateTrendArrays($yValues, $xValues); } catch (Exception $e) { diff --git a/tests/data/Calculation/Statistical/BETADIST.php b/tests/data/Calculation/Statistical/BETADIST.php index 2046e189..ef89575f 100644 --- a/tests/data/Calculation/Statistical/BETADIST.php +++ b/tests/data/Calculation/Statistical/BETADIST.php @@ -29,6 +29,10 @@ return [ 0.4059136, 0.4, 4, 5, ], + [ + 0.4059136, + 0.4, 4, 5, null, null, + ], [ '#VALUE!', 'NAN', 8, 10, 1, 3, diff --git a/tests/data/Calculation/Statistical/BETAINV.php b/tests/data/Calculation/Statistical/BETAINV.php index 4d8cb5bd..609c2804 100644 --- a/tests/data/Calculation/Statistical/BETAINV.php +++ b/tests/data/Calculation/Statistical/BETAINV.php @@ -25,6 +25,10 @@ return [ 0.303225844664, 0.2, 4, 5, 0, 1, ], + [ + 0.303225844664, + 0.2, 4, 5, null, null, + ], [ '#VALUE!', 'NAN', 4, 5, 0, 1, diff --git a/tests/data/Calculation/Statistical/BINOMDISTRANGE.php b/tests/data/Calculation/Statistical/BINOMDISTRANGE.php index 26658b66..153706d1 100644 --- a/tests/data/Calculation/Statistical/BINOMDISTRANGE.php +++ b/tests/data/Calculation/Statistical/BINOMDISTRANGE.php @@ -25,6 +25,10 @@ return [ 0.079589237387, 100, 0.5, 50, ], + [ + 0.079589237387, + 100, 0.5, 50, null, + ], [ '#VALUE!', 'NaN', 0.5, 50, 100, diff --git a/tests/data/Calculation/Statistical/ZTEST.php b/tests/data/Calculation/Statistical/ZTEST.php index 71353f08..9de2a837 100644 --- a/tests/data/Calculation/Statistical/ZTEST.php +++ b/tests/data/Calculation/Statistical/ZTEST.php @@ -37,6 +37,12 @@ return [ [24, 22, 19, 21, 18, 19, 20, 23], 22, ], + [ + 0.952209647727, + [24, 22, 19, 21, 18, 19, 20, 23], + 22, + null, + ], [ '#VALUE!', [1, 2, 3, 3, 4, 4, 8, 10, 12], From edca1f573d437a2ebdf75949797a91afa5c28d05 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Tue, 13 Apr 2021 17:24:45 +0200 Subject: [PATCH 184/187] Use validation classes rather than traits for Engineering functions (#2001) * Use validation classes rather than traits for Engineering functions * Re-baseline phpstan --- phpstan-baseline.neon | 90 ------------------- .../Calculation/Engineering/BesselI.php | 10 +-- .../Calculation/Engineering/BesselJ.php | 10 +-- .../Calculation/Engineering/BesselK.php | 10 +-- .../Calculation/Engineering/BesselY.php | 10 +-- .../Calculation/Engineering/Compare.php | 10 +-- .../Calculation/Engineering/Complex.php | 6 +- ...dations.php => EngineeringValidations.php} | 14 ++- 8 files changed, 32 insertions(+), 128 deletions(-) rename src/PhpSpreadsheet/Calculation/Engineering/{BaseValidations.php => EngineeringValidations.php} (61%) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4e5b7385..1c6070ab 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -490,36 +490,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Engineering.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselI\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselI.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselI\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselI.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselI.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselJ\\:\\:besselj2a\\(\\) has no return typehint specified\\.$#" count: 1 @@ -530,71 +500,11 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselK\\:\\:besselK2\\(\\) has no return typehint specified\\.$#" count: 1 path: src/PhpSpreadsheet/Calculation/Engineering/BesselK.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselY\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselY.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BesselY\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselY.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/BesselY.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Compare\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/Compare.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Compare\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/Compare.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/Compare.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Complex\\:\\:validateFloat\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\Complex\\:\\:validateInt\\(\\) has parameter \\$value with no typehint specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php - - - - message: "#^Parameter \\#1 \\$number of function floor expects float, float\\|int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Engineering/Complex.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Engineering\\\\BitWise\\:\\:validateBitwiseArgument\\(\\) never returns int so it can be removed from the return typehint\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php index bbb24bd4..ea2577cd 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselI.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselI { - use BaseValidations; - /** * BESSELI. * @@ -32,12 +30,12 @@ class BesselI */ public static function BESSELI($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); + $x = Functions::flattenSingleValue($x); + $ord = Functions::flattenSingleValue($ord); try { - $x = self::validateFloat($x); - $ord = self::validateInt($ord); + $x = EngineeringValidations::validateFloat($x); + $ord = EngineeringValidations::validateInt($ord); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php index 730e2870..7ea45a74 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselJ.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselJ { - use BaseValidations; - /** * BESSELJ. * @@ -31,12 +29,12 @@ class BesselJ */ public static function BESSELJ($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord); + $x = Functions::flattenSingleValue($x); + $ord = Functions::flattenSingleValue($ord); try { - $x = self::validateFloat($x); - $ord = self::validateInt($ord); + $x = EngineeringValidations::validateFloat($x); + $ord = EngineeringValidations::validateInt($ord); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php index 18a2ac5c..8facdffc 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselK.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselK { - use BaseValidations; - /** * BESSELK. * @@ -29,12 +27,12 @@ class BesselK */ public static function BESSELK($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); + $x = Functions::flattenSingleValue($x); + $ord = Functions::flattenSingleValue($ord); try { - $x = self::validateFloat($x); - $ord = self::validateInt($ord); + $x = EngineeringValidations::validateFloat($x); + $ord = EngineeringValidations::validateInt($ord); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php index 19932c64..7f387497 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/BesselY.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class BesselY { - use BaseValidations; - /** * BESSELY. * @@ -28,12 +26,12 @@ class BesselY */ public static function BESSELY($x, $ord) { - $x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); - $ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord); + $x = Functions::flattenSingleValue($x); + $ord = Functions::flattenSingleValue($ord); try { - $x = self::validateFloat($x); - $ord = self::validateInt($ord); + $x = EngineeringValidations::validateFloat($x); + $ord = EngineeringValidations::validateInt($ord); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Compare.php b/src/PhpSpreadsheet/Calculation/Engineering/Compare.php index c764d8ea..0a634206 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Compare.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Compare.php @@ -7,8 +7,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Compare { - use BaseValidations; - /** * DELTA. * @@ -31,8 +29,8 @@ class Compare $b = Functions::flattenSingleValue($b); try { - $a = self::validateFloat($a); - $b = self::validateFloat($b); + $a = EngineeringValidations::validateFloat($a); + $b = EngineeringValidations::validateFloat($b); } catch (Exception $e) { return $e->getMessage(); } @@ -61,8 +59,8 @@ class Compare $step = Functions::flattenSingleValue($step); try { - $number = self::validateFloat($number); - $step = self::validateFloat($step); + $number = EngineeringValidations::validateFloat($number); + $step = EngineeringValidations::validateFloat($step); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php index f2718e4a..1c2f5f77 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/Complex.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/Complex.php @@ -9,8 +9,6 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions; class Complex { - use BaseValidations; - /** * COMPLEX. * @@ -33,8 +31,8 @@ class Complex $suffix = ($suffix === null) ? 'i' : Functions::flattenSingleValue($suffix); try { - $realNumber = self::validateFloat($realNumber); - $imaginary = self::validateFloat($imaginary); + $realNumber = EngineeringValidations::validateFloat($realNumber); + $imaginary = EngineeringValidations::validateFloat($imaginary); } catch (Exception $e) { return $e->getMessage(); } diff --git a/src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php b/src/PhpSpreadsheet/Calculation/Engineering/EngineeringValidations.php similarity index 61% rename from src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php rename to src/PhpSpreadsheet/Calculation/Engineering/EngineeringValidations.php index 48317635..01630af3 100644 --- a/src/PhpSpreadsheet/Calculation/Engineering/BaseValidations.php +++ b/src/PhpSpreadsheet/Calculation/Engineering/EngineeringValidations.php @@ -5,9 +5,12 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -trait BaseValidations +class EngineeringValidations { - protected static function validateFloat($value): float + /** + * @param mixed $value + */ + public static function validateFloat($value): float { if (!is_numeric($value)) { throw new Exception(Functions::VALUE()); @@ -16,12 +19,15 @@ trait BaseValidations return (float) $value; } - protected static function validateInt($value): int + /** + * @param mixed $value + */ + public static function validateInt($value): int { if (!is_numeric($value)) { throw new Exception(Functions::VALUE()); } - return (int) floor($value); + return (int) floor((float) $value); } } From 818b993f2e3f0ba54551ce4c916cf2082bda1353 Mon Sep 17 00:00:00 2001 From: jarrett jordaan Date: Sun, 18 Apr 2021 12:14:01 +0200 Subject: [PATCH 185/187] Check array key exists before access in Xlsx.php (#1970) When loading an xlsx file which has images that use a URL, there's a PHP Notice that is shown. Added a check for the existence of the array key for accessing. --- CHANGELOG.md | 1 + src/PhpSpreadsheet/Reader/Xlsx.php | 37 +++++++++++++++++++----------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69d1652a..5d530735 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fixed issue where array key check for existince before accessing arrays in Xlsx.php. [PR #1970](https://github.com/PHPOffice/PhpSpreadsheet/pull/1970) - Fixed issue with quoted strings in number format mask rendered with toFormattedString() [Issue 1972#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1972) [PR #1978](https://github.com/PHPOffice/PhpSpreadsheet/pull/1978) - Fixed issue with percentage formats in number format mask rendered with toFormattedString() [Issue 1929#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1929) [PR #1928](https://github.com/PHPOffice/PhpSpreadsheet/pull/1928) - Fixed issue with _ spacing character in number format mask corrupting output from toFormattedString() [Issue 1924#](https://github.com/PHPOffice/PhpSpreadsheet/issues/1924) [PR #1927](https://github.com/PHPOffice/PhpSpreadsheet/pull/1927) diff --git a/src/PhpSpreadsheet/Reader/Xlsx.php b/src/PhpSpreadsheet/Reader/Xlsx.php index cd0fd149..3895358a 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx.php +++ b/src/PhpSpreadsheet/Reader/Xlsx.php @@ -1134,15 +1134,20 @@ class Xlsx extends BaseReader $objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing(); $objDrawing->setName((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name')); $objDrawing->setDescription((string) self::getArrayItem($oneCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr')); - $objDrawing->setPath( - 'zip://' . File::realpath($pFilename) . '#' . - $images[(string) self::getArrayItem( - $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), - 'embed' - )], - false + $imageKey = (string) self::getArrayItem( + $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), + 'embed' ); + + if (isset($images[$imageKey])) { + $objDrawing->setPath( + 'zip://' . File::realpath($pFilename) . '#' . + $images[$imageKey], + false + ); + } $objDrawing->setCoordinates(Coordinate::stringFromColumnIndex(((int) $oneCellAnchor->from->col) + 1) . ($oneCellAnchor->from->row + 1)); + $objDrawing->setOffsetX(Drawing::EMUToPixels($oneCellAnchor->from->colOff)); $objDrawing->setOffsetY(Drawing::EMUToPixels($oneCellAnchor->from->rowOff)); $objDrawing->setResizeProportional(false); @@ -1200,15 +1205,19 @@ class Xlsx extends BaseReader $objDrawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing(); $objDrawing->setName((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'name')); $objDrawing->setDescription((string) self::getArrayItem($twoCellAnchor->pic->nvPicPr->cNvPr->attributes(), 'descr')); - $objDrawing->setPath( - 'zip://' . File::realpath($pFilename) . '#' . - $images[(string) self::getArrayItem( - $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), - 'embed' - )], - false + $imageKey = (string) self::getArrayItem( + $blip->attributes('http://schemas.openxmlformats.org/officeDocument/2006/relationships'), + 'embed' ); + if (isset($images[$imageKey])) { + $objDrawing->setPath( + 'zip://' . File::realpath($pFilename) . '#' . + $images[$imageKey], + false + ); + } $objDrawing->setCoordinates(Coordinate::stringFromColumnIndex(((int) $twoCellAnchor->from->col) + 1) . ($twoCellAnchor->from->row + 1)); + $objDrawing->setOffsetX(Drawing::EMUToPixels($twoCellAnchor->from->colOff)); $objDrawing->setOffsetY(Drawing::EMUToPixels($twoCellAnchor->from->rowOff)); $objDrawing->setResizeProportional(false); From f49a951bea261d8af883f88937cb8405721da938 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 18 Apr 2021 12:19:53 +0200 Subject: [PATCH 186/187] Tag deprecations for MathTrig, and eliminate calls to the deprecated methods (#2005) * Tag deprecations for MathTrig, and eliminate calls to the deprecated methods --- phpstan-baseline.neon | 5 - .../Calculation/Calculation.php | 6 +- src/PhpSpreadsheet/Calculation/MathTrig.php | 372 +++++++++++++----- .../Calculation/MathTrig/Logarithms.php | 2 - .../Calculation/MathTrig/MatrixFunctions.php | 6 +- .../Calculation/MathTrig/Mod.php | 22 +- .../Statistical/Distributions/Binomial.php | 15 +- .../Distributions/HyperGeometric.php | 13 +- .../Functions/MathTrig/MInverseTest.php | 2 +- .../Functions/MathTrig/MMultTest.php | 2 +- .../Functions/MathTrig/MUnitTest.php | 6 +- 11 files changed, 323 insertions(+), 128 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 1c6070ab..ffe8fdf5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1555,11 +1555,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php - - - message: "#^Binary operation \"\\*\" between int\\|string and int\\|string results in an error\\.$#" - count: 1 - path: src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Calculation\\\\Statistical\\\\Distributions\\\\Normal\\:\\:inverseNcdf\\(\\) has no return typehint specified\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php index dfaa566a..e1deeb6a 100644 --- a/src/PhpSpreadsheet/Calculation/Calculation.php +++ b/src/PhpSpreadsheet/Calculation/Calculation.php @@ -1636,7 +1636,7 @@ class Calculation ], 'MDETERM' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMDeterm'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'determinant'], 'argumentCount' => '1', ], 'MDURATION' => [ @@ -1686,7 +1686,7 @@ class Calculation ], 'MINVERSE' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMinverse'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'inverse'], 'argumentCount' => '1', ], 'MIRR' => [ @@ -1696,7 +1696,7 @@ class Calculation ], 'MMULT' => [ 'category' => Category::CATEGORY_MATH_AND_TRIG, - 'functionCall' => [MathTrig\MatrixFunctions::class, 'funcMMult'], + 'functionCall' => [MathTrig\MatrixFunctions::class, 'multiply'], 'argumentCount' => '2', ], 'MOD' => [ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig.php b/src/PhpSpreadsheet/Calculation/MathTrig.php index 7f30edeb..131f1dbb 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig.php @@ -9,11 +9,14 @@ class MathTrig * * Converts a Roman numeral to an Arabic numeral. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Arabic class instead - * * Excel Function: * ARABIC(text) * + * @Deprecated 1.18.0 + * + * @See MathTrig\Arabic::evaluate() + * Use the evaluate method in the MathTrig\Arabic class instead + * * @param string $roman * * @return int|string the arabic numberal contrived from the roman numeral @@ -36,11 +39,14 @@ class MathTrig * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard * PHP atan2() function, so we need to reverse them here before calling the PHP atan() function. * - * @Deprecated 2.0.0 Use the funcAtan2 method in the MathTrig\Atan2 class instead - * * Excel Function: * ATAN2(xCoordinate,yCoordinate) * + * @Deprecated 1.18.0 + * + * @See MathTrig\Atan2::funcAtan2() + * Use the funcAtan2 method in the MathTrig\Atan2 class instead + * * @param float $xCoordinate the x-coordinate of the point * @param float $yCoordinate the y-coordinate of the point * @@ -56,11 +62,14 @@ class MathTrig * * Converts a number into a text representation with the given radix (base). * - * @Deprecated 2.0.0 Use the funcBase method in the MathTrig\Base class instead - * * Excel Function: * BASE(Number, Radix [Min_length]) * + * @Deprecated 1.18.0 + * + * @See MathTrig\Base::funcBase() + * Use the funcBase method in the MathTrig\Base class instead + * * @param float $number * @param float $radix * @param int $minLength @@ -85,7 +94,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcCeiling() method in the MathTrig\Ceiling class instead + * @see MathTrig\Ceiling::funcCeiling() + * Use the funcCeiling() method in the MathTrig\Ceiling class instead * * @param float $number the number you want to round * @param float $significance the multiple to which you want to round @@ -103,11 +113,14 @@ class MathTrig * Returns the number of combinations for a given number of items. Use COMBIN to * determine the total possible number of groups for a given number of items. * - * @Deprecated 2.0.0 Use the without method in the MathTrig\Combinations class instead - * * Excel Function: * COMBIN(numObjs,numInSet) * + * @Deprecated 1.18.0 + * + * @see MathTrig\Combinations::withoutRepetition() + * Use the withoutRepetition() method in the MathTrig\Combinations class instead + * * @param int $numObjs Number of different objects * @param int $numInSet Number of objects in each combination * @@ -121,8 +134,6 @@ class MathTrig /** * EVEN. * - * @Deprecated 2.0.0 Use the funcEven method in the MathTrig\Even class instead - * * Returns number rounded up to the nearest even integer. * You can use this function for processing items that come in twos. For example, * a packing crate accepts rows of one or two items. The crate is full when @@ -132,6 +143,11 @@ class MathTrig * Excel Function: * EVEN(number) * + * @Deprecated 1.18.0 + * + * @see MathTrig\Even::funcEven() + * Use the funcEven() method in the MathTrig\Even class instead + * * @param float $number Number to round * * @return int|string Rounded Number, or a string containing an error @@ -144,7 +160,10 @@ class MathTrig /** * Helper function for Even. * - * @Deprecated 2.0.0 Use the getEven method in the MathTrig\Helpers class instead + * @Deprecated 1.18.0 + * + * @see MathTrig\Helpers::getEven() + * Use the funcEven() method in the MathTrig\Helpers class instead */ public static function getEven(float $number): int { @@ -157,11 +176,14 @@ class MathTrig * Returns the factorial of a number. * The factorial of a number is equal to 1*2*3*...* number. * - * @Deprecated 2.0.0 Use the funcFact method in the MathTrig\Fact class instead - * * Excel Function: * FACT(factVal) * + * @Deprecated 1.18.0 + * + * @see MathTrig\Fact::funcFact() + * Use the funcFact() method in the MathTrig\Fact class instead + * * @param float $factVal Factorial Value * * @return int|string Factorial, or a string containing an error @@ -176,11 +198,14 @@ class MathTrig * * Returns the double factorial of a number. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\FactDouble class instead - * * Excel Function: * FACTDOUBLE(factVal) * + * @Deprecated 1.18.0 + * + * @see MathTrig\FactDouble::evaluate() + * Use the evaluate() method in the MathTrig\FactDouble class instead + * * @param float $factVal Factorial Value * * @return int|string Double Factorial, or a string containing an error @@ -200,7 +225,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcFloor() method in the MathTrig\Floor class instead + * @see MathTrig\Floor::funcFloor() + * Use the funcFloor() method in the MathTrig\Floor class instead * * @param float $number Number to round * @param float $significance Significance @@ -222,7 +248,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcFloorMath() method in the MathTrig\FloorMath class instead + * @see MathTrig\FloorMath::funcFloorMath() + * Use the funcFloorMath() method in the MathTrig\FloorMath class instead * * @param float $number Number to round * @param float $significance Significance @@ -245,7 +272,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcFloorPrecise() method in the MathTrig\FloorPrecise class instead + * @see MathTrig\FloorPrecise::funcFloorPrecise() + * Use the funcFloorPrecise() method in the MathTrig\FloorPrecise class instead * * @param float $number Number to round * @param float $significance Significance @@ -267,7 +295,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcInt() method in the MathTrig\IntClass class instead + * @see MathTrig\IntClass::funcInt() + * Use the funcInt() method in the MathTrig\IntClass class instead * * @param float $number Number to cast to an integer * @@ -285,11 +314,14 @@ class MathTrig * The greatest common divisor is the largest integer that divides both * number1 and number2 without a remainder. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Gcd class instead - * * Excel Function: * GCD(number1[,number2[, ...]]) * + * @Deprecated 1.18.0 + * + * @see MathTrig\Gcd::evaluate() + * Use the evaluate() method in the MathTrig\Gcd class instead + * * @param mixed ...$args Data values * * @return int|mixed|string Greatest Common Divisor, or a string containing an error @@ -307,11 +339,14 @@ class MathTrig * of all integer arguments number1, number2, and so on. Use LCM to add fractions * with different denominators. * - * @Deprecated 2.0.0 Use the funcLcm method in the MathTrig\Lcm class instead - * * Excel Function: * LCM(number1[,number2[, ...]]) * + * @Deprecated 1.18.0 + * + * @see MathTrig\Lcm::funcLcm() + * Use the funcLcm() method in the MathTrig\Lcm class instead + * * @param mixed ...$args Data values * * @return int|string Lowest Common Multiplier, or a string containing an error @@ -326,11 +361,14 @@ class MathTrig * * Returns the logarithm of a number to a specified base. The default base is 10. * - * @Deprecated 2.0.0 Use the withBase method in the MathTrig\Logarithms class instead - * * Excel Function: * LOG(number[,base]) * + * @Deprecated 1.18.0 + * + * @see MathTrig\Logarithms::withBase() + * Use the withBase() method in the MathTrig\Logarithms class instead + * * @param float $number The positive real number for which you want the logarithm * @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10. * @@ -346,18 +384,21 @@ class MathTrig * * Returns the matrix determinant of an array. * - * @Deprecated 2.0.0 Use the funcMDeterm method in the MathTrig\MatrixFuncs class instead - * * Excel Function: * MDETERM(array) * + * @Deprecated 1.18.0 + * + * @see MathTrig\MatrixFunctions::determinant() + * Use the determinant() method in the MathTrig\MatrixFunctions class instead + * * @param array $matrixValues A matrix of values * * @return float|string The result, or a string containing an error */ public static function MDETERM($matrixValues) { - return MathTrig\MatrixFunctions::funcMDeterm($matrixValues); + return MathTrig\MatrixFunctions::determinant($matrixValues); } /** @@ -365,24 +406,30 @@ class MathTrig * * Returns the inverse matrix for the matrix stored in an array. * - * @Deprecated 2.0.0 Use the funcMInverse method in the MathTrig\MatrixFuncs class instead - * * Excel Function: * MINVERSE(array) * + * @Deprecated 1.18.0 + * + * @see MathTrig\MatrixFunctions::inverse() + * Use the inverse() method in the MathTrig\MatrixFunctions class instead + * * @param array $matrixValues A matrix of values * * @return array|string The result, or a string containing an error */ public static function MINVERSE($matrixValues) { - return MathTrig\MatrixFunctions::funcMInverse($matrixValues); + return MathTrig\MatrixFunctions::inverse($matrixValues); } /** * MMULT. * - * @Deprecated 2.0.0 Use the funcMMult method in the MathTrig\MatrixFuncs class instead + * @Deprecated 1.18.0 + * + * @see MathTrig\MatrixFunctions::multiply() + * Use the multiply() method in the MathTrig\MatrixFunctions class instead * * @param array $matrixData1 A matrix of values * @param array $matrixData2 A matrix of values @@ -391,13 +438,16 @@ class MathTrig */ public static function MMULT($matrixData1, $matrixData2) { - return MathTrig\MatrixFunctions::funcMMult($matrixData1, $matrixData2); + return MathTrig\MatrixFunctions::multiply($matrixData1, $matrixData2); } /** * MOD. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Mod class instead + * @Deprecated 1.18.0 + * + * @see MathTrig\Mod::evaluate() + * Use the evaluate() method in the MathTrig\Mod class instead * * @param int $a Dividend * @param int $b Divisor @@ -416,7 +466,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcMround() method in the MathTrig\Mround class instead + * @see MathTrig\Mround::funcMround() + * Use the funcMround() method in the MathTrig\Mround class instead * * @param float $number Number to round * @param int $multiple Multiple to which you want to round $number @@ -433,7 +484,10 @@ class MathTrig * * Returns the ratio of the factorial of a sum of values to the product of factorials. * - * @Deprecated 2.0.0 Use the funcMultinomial method in the MathTrig\Multinomial class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Multinomial::funcMultinomial() + * Use the funcMultinomial method in the MathTrig\Multinomial class instead * * @param mixed[] $args An array of mixed values for the Data Series * @@ -449,7 +503,10 @@ class MathTrig * * Returns number rounded up to the nearest odd integer. * - * @Deprecated 2.0.0 Use the funcOdd method in the MathTrig\Odd class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Odd::funcOdd() + * Use the funcOdd method in the MathTrig\Odd class instead * * @param float $number Number to round * @@ -465,7 +522,10 @@ class MathTrig * * Computes x raised to the power y. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Power class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Power::evaluate() + * Use the evaluate method in the MathTrig\Power class instead * * @param float $x * @param float $y @@ -482,7 +542,10 @@ class MathTrig * * PRODUCT returns the product of all the values and cells referenced in the argument list. * - * @Deprecated 2.0.0 Use the funcProduct method in the MathTrig\Product class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Product::funcProduct() + * Use the funcProduct method in the MathTrig\Product class instead * * Excel Function: * PRODUCT(value1[,value2[, ...]]) @@ -502,7 +565,10 @@ class MathTrig * QUOTIENT function returns the integer portion of a division. Numerator is the divided number * and denominator is the divisor. * - * @Deprecated 2.0.0 Use the funcQuotient method in the MathTrig\Quotient class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Quotient::funcQuotient() + * Use the funcQuotient method in the MathTrig\Quotient class instead * * Excel Function: * QUOTIENT(value1[,value2[, ...]]) @@ -520,7 +586,10 @@ class MathTrig /** * RAND/RANDBETWEEN. * - * @Deprecated 2.0.0 Use the randNoArg or randBetween method in the MathTrig\Random class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Random::randBetween() + * Use the randBetween or randBetween method in the MathTrig\Random class instead * * @param int $min Minimal value * @param int $max Maximal value @@ -539,7 +608,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcRoman() method in the MathTrig\Roman class instead + * @Ssee MathTrig\Roman::funcRoman() + * Use the funcRoman() method in the MathTrig\Roman class instead * * @param mixed $aValue Number to convert * @param mixed $style Number indicating one of five possible forms @@ -558,7 +628,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcRoundUp() method in the MathTrig\RoundUp class instead + * @See MathTrig\RoundUp::funcRoundUp() + * Use the funcRoundUp() method in the MathTrig\RoundUp class instead * * @param float $number Number to round * @param int $digits Number of digits to which you want to round $number @@ -577,7 +648,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcRoundDown() method in the MathTrig\RoundDown class instead + * @See MathTrig\RoundDown::funcRoundDown() + * Use the funcRoundDown() method in the MathTrig\RoundDown class instead * * @param float $number Number to round * @param int $digits Number of digits to which you want to round $number @@ -594,7 +666,10 @@ class MathTrig * * Returns the sum of a power series * - * @Deprecated 2.0.0 Use the funcSeriesSum method in the MathTrig\SeriesSum class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SeriesSum::funcSeriesSum() + * Use the funcSeriesSum method in the MathTrig\SeriesSum class instead * * @param mixed $x Input value * @param mixed $n Initial power @@ -614,7 +689,10 @@ class MathTrig * Determines the sign of a number. Returns 1 if the number is positive, zero (0) * if the number is 0, and -1 if the number is negative. * - * @Deprecated 2.0.0 Use the funcSign method in the MathTrig\Sign class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Sign::funcSign() + * Use the funcSign method in the MathTrig\Sign class instead * * @param float $number Number to round * @@ -628,7 +706,10 @@ class MathTrig /** * returnSign = returns 0/-1/+1. * - * @Deprecated 2.0.0 Use the returnSign method in the MathTrig\Helpers class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Helpers::returnSign() + * Use the returnSign method in the MathTrig\Helpers class instead */ public static function returnSign(float $number): int { @@ -640,7 +721,10 @@ class MathTrig * * Returns the square root of (number * pi). * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\SqrtPi class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SqrtPi::evaluate() + * Use the evaluate method in the MathTrig\SqrtPi class instead * * @param float $number Number * @@ -656,7 +740,10 @@ class MathTrig * * Returns a subtotal in a list or database. * - * @Deprecated 2.0.0 Use the funcSubtotal method in the MathTrig\Subtotal class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Subtotal::funcSubtotal() + * Use the funcSubtotal method in the MathTrig\Subtotal class instead * * @param int $functionType * A number 1 to 11 that specifies which function to @@ -679,7 +766,10 @@ class MathTrig * * SUM computes the sum of all the values and cells referenced in the argument list. * - * @Deprecated 2.0.0 Use the funcSumNoStrings method in the MathTrig\Sum class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Sum::funcSumNoStrings() + * Use the funcSumNoStrings method in the MathTrig\Sum class instead * * Excel Function: * SUM(value1[,value2[, ...]]) @@ -745,7 +835,10 @@ class MathTrig * Excel Function: * SUMPRODUCT(value1[,value2[, ...]]) * - * @Deprecated 2.0.0 Use the funcSumProduct method in the MathTrig\SumProduct class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SumProduct::funcSumProduct() + * Use the funcSumProduct method in the MathTrig\SumProduct class instead * * @param mixed ...$args Data values * @@ -761,7 +854,10 @@ class MathTrig * * SUMSQ returns the sum of the squares of the arguments * - * @Deprecated 2.0.0 Use the sumSquare method in the MathTrig\SumSquares class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SumSquares::sumSquare() + * Use the sumSquare method in the MathTrig\SumSquares class instead * * Excel Function: * SUMSQ(value1[,value2[, ...]]) @@ -778,7 +874,10 @@ class MathTrig /** * SUMX2MY2. * - * @Deprecated 2.0.0 Use the sumXSquaredMinusYSquared method in the MathTrig\SumSquares class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SumSquares::sumXSquaredMinusYSquared() + * Use the sumXSquaredMinusYSquared method in the MathTrig\SumSquares class instead * * @param mixed[] $matrixData1 Matrix #1 * @param mixed[] $matrixData2 Matrix #2 @@ -793,7 +892,10 @@ class MathTrig /** * SUMX2PY2. * - * @Deprecated 2.0.0 Use the sumXSquaredPlusYSquared method in the MathTrig\SumSquares class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SumSquares::sumXSquaredPlusYSquared() + * Use the sumXSquaredPlusYSquared method in the MathTrig\SumSquares class instead * * @param mixed[] $matrixData1 Matrix #1 * @param mixed[] $matrixData2 Matrix #2 @@ -808,7 +910,10 @@ class MathTrig /** * SUMXMY2. * - * @Deprecated 2.0.0 Use the sumXMinusYSquared method in the MathTrig\SumSquares class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SumSquares::sumXMinusYSquared() + * Use the sumXMinusYSquared method in the MathTrig\SumSquares class instead * * @param mixed[] $matrixData1 Matrix #1 * @param mixed[] $matrixData2 Matrix #2 @@ -827,7 +932,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the funcTrunc() method in the MathTrig\Trunc class instead + * @see MathTrig\Trunc::funcTrunc() + * Use the funcTrunc() method in the MathTrig\Trunc class instead * * @param float $value * @param int $digits @@ -844,7 +950,10 @@ class MathTrig * * Returns the secant of an angle. * - * @Deprecated 2.0.0 Use the funcSec method in the MathTrig\Sec class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Sec::funcSec() + * Use the funcSec method in the MathTrig\Sec class instead * * @param float $angle Number * @@ -860,7 +969,10 @@ class MathTrig * * Returns the hyperbolic secant of an angle. * - * @Deprecated 2.0.0 Use the funcSech method in the MathTrig\Sech class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\SecH::funcSech() + * Use the funcSecH method in the MathTrig\Sech class instead * * @param float $angle Number * @@ -876,7 +988,10 @@ class MathTrig * * Returns the cosecant of an angle. * - * @Deprecated 2.0.0 Use the funcCsc method in the MathTrig\Csc class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Csc::funcCsc() + * Use the funcCsc method in the MathTrig\Csc class instead * * @param float $angle Number * @@ -892,7 +1007,10 @@ class MathTrig * * Returns the hyperbolic cosecant of an angle. * - * @Deprecated 2.0.0 Use the funcCsch method in the MathTrig\Csch class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Csch::funcCsch() + * Use the funcCsch method in the MathTrig\Csch class instead * * @param float $angle Number * @@ -908,7 +1026,10 @@ class MathTrig * * Returns the cotangent of an angle. * - * @Deprecated 2.0.0 Use the funcCot method in the MathTrig\Cot class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Cot::funcCot() + * Use the funcCot method in the MathTrig\Cot class instead * * @param float $angle Number * @@ -924,7 +1045,10 @@ class MathTrig * * Returns the hyperbolic cotangent of an angle. * - * @Deprecated 2.0.0 Use the funcCoth method in the MathTrig\Coth class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Coth::funcCoth() + * Use the funcCoth method in the MathTrig\Coth class instead * * @param float $angle Number * @@ -940,7 +1064,10 @@ class MathTrig * * Returns the arccotangent of a number. * - * @Deprecated 2.0.0 Use the funcAcot method in the MathTrig\Acot class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Acot::funcAcot() + * Use the funcAcot method in the MathTrig\Acot class instead * * @param float $number Number * @@ -954,7 +1081,10 @@ class MathTrig /** * Return NAN or value depending on argument. * - * @Deprecated 2.0.0 Use the numberOrNan method in the MathTrig\Helpers class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Helpers::numberOrNan() + * Use the numberOrNan method in the MathTrig\Helpers class instead * * @param float $result Number * @@ -970,7 +1100,10 @@ class MathTrig * * Returns the hyperbolic arccotangent of a number. * - * @Deprecated 2.0.0 Use the funcAcoth method in the MathTrig\Acoth class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Acoth::funcAcoth() + * Use the funcAcoth method in the MathTrig\Acoth class instead * * @param float $number Number * @@ -988,7 +1121,8 @@ class MathTrig * * @Deprecated 1.17.0 * - * @see Use the builtinRound() method in the MathTrig\Round class instead + * @See MathTrig\Round::builtinROUND() + * Use the builtinRound() method in the MathTrig\Round class instead * * @param mixed $number Should be numeric * @param mixed $precision Should be int @@ -1005,7 +1139,10 @@ class MathTrig * * Returns the result of builtin function abs after validating args. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Absolute class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Absolute::evaluate() + * Use the evaluate method in the MathTrig\Absolute class instead * * @param mixed $number Should be numeric * @@ -1019,7 +1156,10 @@ class MathTrig /** * ACOS. * - * @Deprecated 2.0.0 Use the funcAcos method in the MathTrig\Acos class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Acos::funcAcos() + * Use the funcAcos method in the MathTrig\Acos class instead * * Returns the result of builtin function acos after validating args. * @@ -1037,7 +1177,10 @@ class MathTrig * * Returns the result of builtin function acosh after validating args. * - * @Deprecated 2.0.0 Use the funcAcosh method in the MathTrig\Acosh class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Acosh::funcAcosh() + * Use the funcAcosh method in the MathTrig\Acosh class instead * * @param mixed $number Should be numeric * @@ -1053,7 +1196,10 @@ class MathTrig * * Returns the result of builtin function asin after validating args. * - * @Deprecated 2.0.0 Use the funcAsin method in the MathTrig\Asin class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Asin::funcAsin() + * Use the funcAsin method in the MathTrig\Asin class instead * * @param mixed $number Should be numeric * @@ -1069,7 +1215,10 @@ class MathTrig * * Returns the result of builtin function asinh after validating args. * - * @Deprecated 2.0.0 Use the funcAsinh method in the MathTrig\Asinh class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Asinh::funcAsinh() + * Use the funcAsinh method in the MathTrig\Asinh class instead * * @param mixed $number Should be numeric * @@ -1085,7 +1234,10 @@ class MathTrig * * Returns the result of builtin function atan after validating args. * - * @Deprecated 2.0.0 Use the funcAtan method in the MathTrig\Atan class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Atan::funcAtan() + * Use the funcAtan method in the MathTrig\Atan class instead * * @param mixed $number Should be numeric * @@ -1101,7 +1253,10 @@ class MathTrig * * Returns the result of builtin function atanh after validating args. * - * @Deprecated 2.0.0 Use the funcAtanh method in the MathTrig\Atanh class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Atanh::funcAtanh() + * Use the funcAtanh method in the MathTrig\Atanh class instead * * @param mixed $number Should be numeric * @@ -1117,7 +1272,10 @@ class MathTrig * * Returns the result of builtin function cos after validating args. * - * @Deprecated 2.0.0 Use the funcCos method in the MathTrig\Cos class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Cos::funcCos() + * Use the funcCos method in the MathTrig\Cos class instead * * @param mixed $number Should be numeric * @@ -1133,7 +1291,10 @@ class MathTrig * * Returns the result of builtin function cos after validating args. * - * @Deprecated 2.0.0 Use the funcCosh method in the MathTrig\Cosh class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Cosh::funcCosh() + * Use the funcCosh method in the MathTrig\Cosh class instead * * @param mixed $number Should be numeric * @@ -1149,7 +1310,10 @@ class MathTrig * * Returns the result of builtin function rad2deg after validating args. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Degrees class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Degrees::evaluate() + * Use the evaluate method in the MathTrig\Degrees class instead * * @param mixed $number Should be numeric * @@ -1165,7 +1329,10 @@ class MathTrig * * Returns the result of builtin function exp after validating args. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Exp class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Exp::evaluate() + * Use the evaluate method in the MathTrig\Exp class instead * * @param mixed $number Should be numeric * @@ -1181,7 +1348,10 @@ class MathTrig * * Returns the result of builtin function log after validating args. * - * @Deprecated 2.0.0 Use the natural method in the MathTrig\Logarithms class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Logarithms::natural() + * Use the natural method in the MathTrig\Logarithms class instead * * @param mixed $number Should be numeric * @@ -1197,7 +1367,10 @@ class MathTrig * * Returns the result of builtin function log after validating args. * - * @Deprecated 2.0.0 Use the base10 method in the MathTrig\Logarithms class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Logarithms::base10() + * Use the natural method in the MathTrig\Logarithms class instead * * @param mixed $number Should be numeric * @@ -1213,7 +1386,10 @@ class MathTrig * * Returns the result of builtin function deg2rad after validating args. * - * @Deprecated 2.0.0 Use the funcSin method in the MathTrig\Sin class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Radians::evaluate() + * Use the evaluate method in the MathTrig\Radians class instead * * @param mixed $number Should be numeric * @@ -1227,10 +1403,13 @@ class MathTrig /** * SIN. * - * @Deprecated 2.0.0 Use the funcSin method in the MathTrig\Sin class instead - * * Returns the result of builtin function sin after validating args. * + * @Deprecated 1.18.0 + * + * @See MathTrig\Sin::funcSin() + * Use the funcSin method in the MathTrig\Sin class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number @@ -1243,10 +1422,13 @@ class MathTrig /** * SINH. * - * @Deprecated 2.0.0 Use the funcSinh method in the MathTrig\Sinh class instead - * * Returns the result of builtin function sinh after validating args. * + * @Deprecated 1.18.0 + * + * @See MathTrig\Sinh::funcSinh() + * Use the funcSinh method in the MathTrig\Sinh class instead + * * @param mixed $number Should be numeric * * @return float|string Rounded number @@ -1261,7 +1443,10 @@ class MathTrig * * Returns the result of builtin function sqrt after validating args. * - * @Deprecated 2.0.0 Use the evaluate method in the MathTrig\Sqrt class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Sqrt::evaluate() + * Use the evaluate method in the MathTrig\Sqrt class instead * * @param mixed $number Should be numeric * @@ -1277,7 +1462,10 @@ class MathTrig * * Returns the result of builtin function tan after validating args. * - * @Deprecated 2.0.0 Use the funcTan method in the MathTrig\Tan class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Tan::funcTan() + * Use the funcTan method in the MathTrig\Tan class instead * * @param mixed $number Should be numeric * @@ -1293,7 +1481,10 @@ class MathTrig * * Returns the result of builtin function sinh after validating args. * - * @Deprecated 2.0.0 Use the funcTanh method in the MathTrig\Tanh class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Tan::funcTan() + * Use the funcTanh method in the MathTrig\Tanh class instead * * @param mixed $number Should be numeric * @@ -1307,7 +1498,10 @@ class MathTrig /** * Many functions accept null/false/true argument treated as 0/0/1. * - * @Deprecated 2.0.0 Use the validateNumericNullBool method in the MathTrig\Helpers class instead + * @Deprecated 1.18.0 + * + * @See MathTrig\Helpers::validateNumericNullBool() + * Use the validateNumericNullBool method in the MathTrig\Helpers class instead * * @param mixed $number */ diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php b/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php index 356a0937..169a74b0 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Logarithms.php @@ -59,8 +59,6 @@ class Logarithms * * Returns the result of builtin function log after validating args. * - * @Deprecated 2.0.0 Use the natural method in the MathTrig\Logarithms class instead - * * @param mixed $number Should be numeric * * @return float|string Rounded number diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php b/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php index 145adfa0..f0eea049 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/MatrixFunctions.php @@ -53,7 +53,7 @@ class MatrixFunctions * * @return float|string The result, or a string containing an error */ - public static function funcMDeterm($matrixValues) + public static function determinant($matrixValues) { try { $matrix = self::getMatrix($matrixValues); @@ -78,7 +78,7 @@ class MatrixFunctions * * @return array|string The result, or a string containing an error */ - public static function funcMInverse($matrixValues) + public static function inverse($matrixValues) { try { $matrix = self::getMatrix($matrixValues); @@ -99,7 +99,7 @@ class MatrixFunctions * * @return array|string The result, or a string containing an error */ - public static function funcMMult($matrixData1, $matrixData2) + public static function multiply($matrixData1, $matrixData2) { try { $matrixA = self::getMatrix($matrixData1); diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php b/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php index b2e3cf4b..04267ee9 100644 --- a/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php +++ b/src/PhpSpreadsheet/Calculation/MathTrig/Mod.php @@ -9,28 +9,28 @@ class Mod /** * MOD. * - * @param mixed $a Dividend - * @param mixed $b Divisor + * @param mixed $dividend Dividend + * @param mixed $divisor Divisor * * @return float|int|string Remainder, or a string containing an error */ - public static function evaluate($a, $b) + public static function evaluate($dividend, $divisor) { try { - $a = Helpers::validateNumericNullBool($a); - $b = Helpers::validateNumericNullBool($b); - Helpers::validateNotZero($b); + $dividend = Helpers::validateNumericNullBool($dividend); + $divisor = Helpers::validateNumericNullBool($divisor); + Helpers::validateNotZero($divisor); } catch (Exception $e) { return $e->getMessage(); } - if (($a < 0.0) && ($b > 0.0)) { - return $b - fmod(abs($a), $b); + if (($dividend < 0.0) && ($divisor > 0.0)) { + return $divisor - fmod(abs($dividend), $divisor); } - if (($a > 0.0) && ($b < 0.0)) { - return $b + fmod($a, abs($b)); + if (($dividend > 0.0) && ($divisor < 0.0)) { + return $divisor + fmod($dividend, abs($divisor)); } - return fmod($a, $b); + return fmod($dividend, $divisor); } } diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php index ffc82afa..9631236a 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/Binomial.php @@ -4,7 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Combinations; class Binomial { @@ -47,7 +47,8 @@ class Binomial return self::calculateCumulativeBinomial($value, $trials, $probability); } - return MathTrig::COMBIN($trials, $value) * $probability ** $value * (1 - $probability) ** ($trials - $value); + return Combinations::withoutRepetition($trials, $value) * $probability ** $value + * (1 - $probability) ** ($trials - $value); } /** @@ -89,7 +90,8 @@ class Binomial $summer = 0; for ($i = $successes; $i <= $limit; ++$i) { - $summer += MathTrig::COMBIN($trials, $i) * $probability ** $i * (1 - $probability) ** ($trials - $i); + $summer += Combinations::withoutRepetition($trials, $i) * $probability ** $i + * (1 - $probability) ** ($trials - $i); } return $summer; @@ -136,8 +138,8 @@ class Binomial } } - return (MathTrig::COMBIN($failures + $successes - 1, $successes - 1)) * - ($probability ** $successes) * ((1 - $probability) ** $failures); + return (Combinations::withoutRepetition($failures + $successes - 1, $successes - 1)) + * ($probability ** $successes) * ((1 - $probability) ** $failures); } /** @@ -191,7 +193,8 @@ class Binomial { $summer = 0; for ($i = 0; $i <= $value; ++$i) { - $summer += MathTrig::COMBIN($trials, $i) * $probability ** $i * (1 - $probability) ** ($trials - $i); + $summer += Combinations::withoutRepetition($trials, $i) * $probability ** $i + * (1 - $probability) ** ($trials - $i); } return $summer; diff --git a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php index b74cfc5f..fe30c087 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php +++ b/src/PhpSpreadsheet/Calculation/Statistical/Distributions/HyperGeometric.php @@ -4,7 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions; use PhpOffice\PhpSpreadsheet\Calculation\Exception; use PhpOffice\PhpSpreadsheet\Calculation\Functions; -use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; +use PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Combinations; class HyperGeometric { @@ -47,8 +47,13 @@ class HyperGeometric return Functions::NAN(); } - return MathTrig::COMBIN($populationSuccesses, $sampleSuccesses) * - MathTrig::COMBIN($populationNumber - $populationSuccesses, $sampleNumber - $sampleSuccesses) / - MathTrig::COMBIN($populationNumber, $sampleNumber); + $successesPopulationAndSample = (float) Combinations::withoutRepetition($populationSuccesses, $sampleSuccesses); + $numbersPopulationAndSample = (float) Combinations::withoutRepetition($populationNumber, $sampleNumber); + $adjustedPopulationAndSample = (float) Combinations::withoutRepetition( + $populationNumber - $populationSuccesses, + $sampleNumber - $sampleSuccesses + ); + + return $successesPopulationAndSample * $adjustedPopulationAndSample / $numbersPopulationAndSample; } } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php index 30a40726..b629d466 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MInverseTest.php @@ -13,7 +13,7 @@ class MInverseTest extends AllSetupTeardown */ public function testMINVERSE($expectedResult, array $args): void { - $result = MathTrig\MatrixFunctions::funcMInverse($args); + $result = MathTrig\MatrixFunctions::inverse($args); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php index 49474c14..e27922c2 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MMultTest.php @@ -13,7 +13,7 @@ class MMultTest extends AllSetupTeardown */ public function testMMULT($expectedResult, ...$args): void { - $result = MathTrig\MatrixFunctions::funcMMult(...$args); + $result = MathTrig\MatrixFunctions::multiply(...$args); self::assertEqualsWithDelta($expectedResult, $result, 1E-8); } diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php index 4e9f95cf..1035dac7 100644 --- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/MUnitTest.php @@ -11,10 +11,10 @@ class MUnitTest extends AllSetupTeardown $identity = MatrixFunctions::funcMUnit(3); self::assertEquals([[1, 0, 0], [0, 1, 0], [0, 0, 1]], $identity); $startArray = [[1, 2, 2], [4, 5, 6], [7, 8, 9]]; - $resultArray = MatrixFunctions::funcMMult($startArray, $identity); + $resultArray = MatrixFunctions::multiply($startArray, $identity); self::assertEquals($startArray, $resultArray); - $inverseArray = MatrixFunctions::funcMInverse($startArray); - $resultArray = MatrixFunctions::funcMMult($startArray, $inverseArray); + $inverseArray = MatrixFunctions::inverse($startArray); + $resultArray = MatrixFunctions::multiply($startArray, $inverseArray); self::assertEquals($identity, $resultArray); self::assertEquals('#VALUE!', MatrixFunctions::funcMUnit(0)); self::assertEquals('#VALUE!', MatrixFunctions::funcMUnit(-1)); From caf11fe80844871b201d5fef47292647c94cdebe Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Sun, 18 Apr 2021 20:09:04 +0200 Subject: [PATCH 187/187] Refactoring to extract DocProperties Reader from Gnumeric Reader (#2007) * Refactoring to extract DocProperties Reader from Gnumeric Reader --- phpstan-baseline.neon | 10 -- src/PhpSpreadsheet/Reader/Gnumeric.php | 145 +-------------- .../Reader/Gnumeric/Properties.php | 167 ++++++++++++++++++ 3 files changed, 169 insertions(+), 153 deletions(-) create mode 100644 src/PhpSpreadsheet/Reader/Gnumeric/Properties.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ffe8fdf5..ced31605 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2875,16 +2875,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setCreated\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - - - message: "#^Parameter \\#1 \\$timestamp of method PhpOffice\\\\PhpSpreadsheet\\\\Document\\\\Properties\\:\\:setModified\\(\\) expects int\\|string\\|null, int\\|false given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Reader/Gnumeric.php - - message: "#^Offset 'No' does not exist on SimpleXMLElement\\|null\\.$#" count: 2 diff --git a/src/PhpSpreadsheet/Reader/Gnumeric.php b/src/PhpSpreadsheet/Reader/Gnumeric.php index dfba56d7..d3cdf1b0 100644 --- a/src/PhpSpreadsheet/Reader/Gnumeric.php +++ b/src/PhpSpreadsheet/Reader/Gnumeric.php @@ -6,6 +6,7 @@ use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\DefinedName; use PhpOffice\PhpSpreadsheet\Reader\Gnumeric\PageSetup; +use PhpOffice\PhpSpreadsheet\Reader\Gnumeric\Properties; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\ReferenceHelper; use PhpOffice\PhpSpreadsheet\RichText\RichText; @@ -262,148 +263,6 @@ class Gnumeric extends BaseReader return self::$mappings; } - private function docPropertiesOld(SimpleXMLElement $gnmXML): void - { - $docProps = $this->spreadsheet->getProperties(); - foreach ($gnmXML->Summary->Item as $summaryItem) { - $propertyName = $summaryItem->name; - $propertyValue = $summaryItem->{'val-string'}; - switch ($propertyName) { - case 'title': - $docProps->setTitle(trim($propertyValue)); - - break; - case 'comments': - $docProps->setDescription(trim($propertyValue)); - - break; - case 'keywords': - $docProps->setKeywords(trim($propertyValue)); - - break; - case 'category': - $docProps->setCategory(trim($propertyValue)); - - break; - case 'manager': - $docProps->setManager(trim($propertyValue)); - - break; - case 'author': - $docProps->setCreator(trim($propertyValue)); - $docProps->setLastModifiedBy(trim($propertyValue)); - - break; - case 'company': - $docProps->setCompany(trim($propertyValue)); - - break; - } - } - } - - private function docPropertiesDC(SimpleXMLElement $officePropertyDC): void - { - $docProps = $this->spreadsheet->getProperties(); - foreach ($officePropertyDC as $propertyName => $propertyValue) { - $propertyValue = trim((string) $propertyValue); - switch ($propertyName) { - case 'title': - $docProps->setTitle($propertyValue); - - break; - case 'subject': - $docProps->setSubject($propertyValue); - - break; - case 'creator': - $docProps->setCreator($propertyValue); - $docProps->setLastModifiedBy($propertyValue); - - break; - case 'date': - $creationDate = strtotime($propertyValue); - $docProps->setCreated($creationDate); - $docProps->setModified($creationDate); - - break; - case 'description': - $docProps->setDescription($propertyValue); - - break; - } - } - } - - private function docPropertiesMeta(SimpleXMLElement $officePropertyMeta, array $namespacesMeta): void - { - $docProps = $this->spreadsheet->getProperties(); - foreach ($officePropertyMeta as $propertyName => $propertyValue) { - $attributes = $propertyValue->attributes($namespacesMeta['meta']); - $propertyValue = trim((string) $propertyValue); - switch ($propertyName) { - case 'keyword': - $docProps->setKeywords($propertyValue); - - break; - case 'initial-creator': - $docProps->setCreator($propertyValue); - $docProps->setLastModifiedBy($propertyValue); - - break; - case 'creation-date': - $creationDate = strtotime($propertyValue); - $docProps->setCreated($creationDate); - $docProps->setModified($creationDate); - - break; - case 'user-defined': - [, $attrName] = explode(':', $attributes['name']); - switch ($attrName) { - case 'publisher': - $docProps->setCompany($propertyValue); - - break; - case 'category': - $docProps->setCategory($propertyValue); - - break; - case 'manager': - $docProps->setManager($propertyValue); - - break; - } - - break; - } - } - } - - private function docProperties(SimpleXMLElement $xml, SimpleXMLElement $gnmXML, array $namespacesMeta): void - { - if (isset($namespacesMeta['office'])) { - $officeXML = $xml->children($namespacesMeta['office']); - $officeDocXML = $officeXML->{'document-meta'}; - $officeDocMetaXML = $officeDocXML->meta; - - foreach ($officeDocMetaXML as $officePropertyData) { - $officePropertyDC = []; - if (isset($namespacesMeta['dc'])) { - $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']); - } - $this->docPropertiesDC($officePropertyDC); - - $officePropertyMeta = []; - if (isset($namespacesMeta['meta'])) { - $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']); - } - $this->docPropertiesMeta($officePropertyMeta, $namespacesMeta); - } - } elseif (isset($gnmXML->Summary)) { - $this->docPropertiesOld($gnmXML); - } - } - private function processComments(SimpleXMLElement $sheet): void { if ((!$this->readDataOnly) && (isset($sheet->Objects))) { @@ -450,7 +309,7 @@ class Gnumeric extends BaseReader $this->gnm = array_key_exists('gmr', $namespacesMeta) ? 'gmr' : 'gnm'; $gnmXML = $xml->children($namespacesMeta[$this->gnm]); - $this->docProperties($xml, $gnmXML, $namespacesMeta); + (new Properties($this->spreadsheet))->readProperties($xml, $gnmXML, $namespacesMeta); $worksheetID = 0; foreach ($gnmXML->Sheets->Sheet as $sheet) { diff --git a/src/PhpSpreadsheet/Reader/Gnumeric/Properties.php b/src/PhpSpreadsheet/Reader/Gnumeric/Properties.php new file mode 100644 index 00000000..16d9c2e0 --- /dev/null +++ b/src/PhpSpreadsheet/Reader/Gnumeric/Properties.php @@ -0,0 +1,167 @@ +spreadsheet = $spreadsheet; + } + + private function docPropertiesOld(SimpleXMLElement $gnmXML): void + { + $docProps = $this->spreadsheet->getProperties(); + foreach ($gnmXML->Summary->Item as $summaryItem) { + $propertyName = $summaryItem->name; + $propertyValue = $summaryItem->{'val-string'}; + switch ($propertyName) { + case 'title': + $docProps->setTitle(trim($propertyValue)); + + break; + case 'comments': + $docProps->setDescription(trim($propertyValue)); + + break; + case 'keywords': + $docProps->setKeywords(trim($propertyValue)); + + break; + case 'category': + $docProps->setCategory(trim($propertyValue)); + + break; + case 'manager': + $docProps->setManager(trim($propertyValue)); + + break; + case 'author': + $docProps->setCreator(trim($propertyValue)); + $docProps->setLastModifiedBy(trim($propertyValue)); + + break; + case 'company': + $docProps->setCompany(trim($propertyValue)); + + break; + } + } + } + + private function docPropertiesDC(SimpleXMLElement $officePropertyDC): void + { + $docProps = $this->spreadsheet->getProperties(); + foreach ($officePropertyDC as $propertyName => $propertyValue) { + $propertyValue = trim((string) $propertyValue); + switch ($propertyName) { + case 'title': + $docProps->setTitle($propertyValue); + + break; + case 'subject': + $docProps->setSubject($propertyValue); + + break; + case 'creator': + $docProps->setCreator($propertyValue); + $docProps->setLastModifiedBy($propertyValue); + + break; + case 'date': + $creationDate = strtotime($propertyValue); + $creationDate = $creationDate === false ? time() : $creationDate; + $docProps->setCreated($creationDate); + $docProps->setModified($creationDate); + + break; + case 'description': + $docProps->setDescription($propertyValue); + + break; + } + } + } + + private function docPropertiesMeta(SimpleXMLElement $officePropertyMeta, array $namespacesMeta): void + { + $docProps = $this->spreadsheet->getProperties(); + foreach ($officePropertyMeta as $propertyName => $propertyValue) { + if ($propertyValue === null) { + continue; + } + + $attributes = $propertyValue->attributes($namespacesMeta['meta']); + $propertyValue = trim((string) $propertyValue); + switch ($propertyName) { + case 'keyword': + $docProps->setKeywords($propertyValue); + + break; + case 'initial-creator': + $docProps->setCreator($propertyValue); + $docProps->setLastModifiedBy($propertyValue); + + break; + case 'creation-date': + $creationDate = strtotime($propertyValue); + $creationDate = $creationDate === false ? time() : $creationDate; + $docProps->setCreated($creationDate); + $docProps->setModified($creationDate); + + break; + case 'user-defined': + [, $attrName] = explode(':', $attributes['name']); + switch ($attrName) { + case 'publisher': + $docProps->setCompany($propertyValue); + + break; + case 'category': + $docProps->setCategory($propertyValue); + + break; + case 'manager': + $docProps->setManager($propertyValue); + + break; + } + + break; + } + } + } + + public function readProperties(SimpleXMLElement $xml, SimpleXMLElement $gnmXML, array $namespacesMeta): void + { + if (isset($namespacesMeta['office'])) { + $officeXML = $xml->children($namespacesMeta['office']); + $officeDocXML = $officeXML->{'document-meta'}; + $officeDocMetaXML = $officeDocXML->meta; + + foreach ($officeDocMetaXML as $officePropertyData) { + $officePropertyDC = []; + if (isset($namespacesMeta['dc'])) { + $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']); + } + $this->docPropertiesDC($officePropertyDC); + + $officePropertyMeta = []; + if (isset($namespacesMeta['meta'])) { + $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']); + } + $this->docPropertiesMeta($officePropertyMeta, $namespacesMeta); + } + } elseif (isset($gnmXML->Summary)) { + $this->docPropertiesOld($gnmXML); + } + } +}