Commit Graph

6555 Commits

Author SHA1 Message Date
Julien Chavée 5083bf023f Merge branch 'master' into master 2026-08-19 22:01:59 +02:00
oleibman 930293a32a Merge pull request #4965 from oleibman/reflect86
Php8.6 Deprecation in Reflection::invokeArgs
2026-08-17 04:01:42 +00:00
oleibman 96d442ab66 Php8.6 Deprecation in Reflection::invokeArgs
Affects one test member, no source code.
2026-08-16 20:55:28 -07:00
oleibman 65b080eef4 Merge pull request #4952 from oleibman/stancomments
Update Phpstan and Tcpdf
2026-08-11 22:20:21 +00:00
oleibman 538ede3aa0 Merge pull request #4959 from oleibman/fix861
First Php8.6 (Extremely Minor) Problem
2026-08-11 04:34:49 +00:00
oleibman ffac2cbe29 First Php8.6 (Extremely Minor) Problem
In 8.6, XmlWriter is declared non-serializable. This changes the result of one unit test (we receive a different exception than we had expected).
2026-08-10 21:27:15 -07:00
Julien Chavée bf9a0210e2 Avoid getStyle on every setValueExplicit quote-prefix check 2026-08-10 11:21:39 +02:00
oleibman 585d3c0ce4 Merge branch 'master' into stancomments 2026-08-09 02:42:11 -07:00
oleibman b9f6ba4667 2.2.7 Reported Internal Error on Win11 - Upgrade to 2.2.8 2026-08-09 02:25:59 -07:00
oleibman 33e837480c Tweaks 2026-08-09 01:20:05 -07:00
oleibman 49affe510f Merge pull request #4954 from gaoflow/fix-betainv-underflow-false-convergence
Fix BETAINV false convergence when the Beta CDF underflows
2026-08-09 07:03:04 +00:00
oleibman 3518d40436 Merge branch 'master' into fix-betainv-underflow-false-convergence 2026-08-08 23:59:16 -07:00
oleibman e91b33a638 Merge pull request #4953 from gaoflow/fix-gamma-large-shape
Fix gamma-family overflow for large shape parameters
2026-08-09 03:57:53 +00:00
oleibman 5278916aab Merge pull request #4935 from kemo/perf/xlsx-writer-cell-fetch
Reduce redundant cell lookups in Xlsx writer hot path
2026-08-09 03:49:27 +00:00
oleibman d46c2ff387 Merge pull request #4955 from PHPOffice/dependabot/composer/squizlabs/php_codesniffer-3.13.6
Bump squizlabs/php_codesniffer from 3.13.5 to 3.13.6
2026-08-08 14:52:10 +00:00
dependabot[bot] 688c44f4db Bump squizlabs/php_codesniffer from 3.13.5 to 3.13.6
Bumps [squizlabs/php_codesniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) from 3.13.5 to 3.13.6.
- [Release notes](https://github.com/PHPCSStandards/PHP_CodeSniffer/releases)
- [Changelog](https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/4.x/CHANGELOG-3.x.md)
- [Commits](https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.13.5...3.13.6)

---
updated-dependencies:
- dependency-name: squizlabs/php_codesniffer
  dependency-version: 3.13.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-08 08:27:06 +00:00
Vincent Gao 52da37f4a7 Fix gamma-family overflow for large shape parameters
GAMMA.INV silently returned the first bisection midpoint for alpha in
~[143, 171.62] (e.g. GAMMA.INV(0.5, 143, 1) gave 358.0 instead of
142.667) and #NUM! above that, because the Newton-step pdf evaluates
Gamma(a), b**a and value**(a-1) in linear domain, all of which overflow
even though the density itself is a small representable number. The same
pattern breaks the GAMMA.DIST, CHISQ.DIST and F.DIST densities and
GAMMALN, which computed log(Gamma(x)) through Gamma(x).

Evaluate these in log domain via the existing logGamma, and scale the
incomplete-gamma series/continued-fraction iteration cap as O(sqrt(a)),
which both expansions need to converge near x ~ a once the shape is
large (GAMMA.INV drifted from the true quantile above alpha ~5000 and
returned alpha+1 by alpha=10000; same for CHISQ.INV at high df).
2026-08-07 01:14:45 +02:00
Vincent Gao 3046ce9214 Add changelog entry for #4954 2026-08-05 12:29:20 +02:00
Vincent Gao f687d261e8 Fix BETAINV false convergence when the Beta CDF underflows
calculateInverse() treated a CDF value of exactly 0.0 as "the guess is the
root" and collapsed the bracket with $b = $a, ending the search. inverse()
already rejects probability <= 0, so a CDF of 0.0 inside the bisection can
only be a float64 underflow at a guess far below the root - never an exact
hit. It is just an ordinary "guess too low" and belongs in the existing
else branch.

The underflow is reached whenever a probe lands many standard deviations
from the mean, so the search collapses after two or three iterations and
returns whichever midpoint it was holding. BETAINV(0.5, 5000, 5000) gave
0.25, though Beta(a, a) is symmetric and its median is exactly 0.5;
BETAINV(0.5, 20000, 3) gave 0.5 against a true 0.99986. Onset is around
alpha = 1080 for beta = 1, where the closed form 0.5 ** (1 / alpha) is
available to check against.

That test also happened to stop the search for shapes where incompleteBeta
declines to evaluate at all and returns 0 for every x, so inverse() now
rejects alpha + beta above that documented limit up front: the CDF is
identically zero there, so no quantile exists to search for.

Tests cover a shape x probability grid against scipy reference values plus
three checks that need no external oracle: the symmetric median, the
Beta(alpha, 1) closed form, and the BETADIST round trip / mirror identity.
2026-08-05 12:28:05 +02:00
oleibman 7e7c5eb2c8 Add Some @var Doc Blocks 2026-08-04 22:34:04 -07:00
oleibman 608da6024e Merge branch 'master' into stancomments 2026-08-04 20:56:58 -07:00
oleibman 3006859ecb Merge pull request #4942 from saifulferoz/feature/pivot-table-read
Feature/pivot table read
2026-08-05 03:22:00 +00:00
oleibman 47aca381d8 Merge pull request #4945 from gaoflow/fix-incomplete-gamma-convergence
Fix incomplete gamma convergence for GAMMA.DIST / CHISQ.DIST
2026-08-05 03:12:07 +00:00
Vincent Gao a0e67af496 Update the now-reachable extreme-tail case for GAMMA.INV
Merging #4946 (bracket expansion) with #4945 (accurate incomplete
gamma) means p=0.9999999 no longer hits the alpha*beta*5 safety
ceiling -- the corrected regularizedGammaP/Q resolve the true root.
Fold it into the extreme-tail data provider against the closed-form
-ln(1-p) check instead of asserting the stale clamped bound.
2026-08-04 08:28:27 +02:00
Vincent Gao 270456a20e test: cover GammaBase::incompleteGamma() directly
It has no remaining callers (kept only for BC) so nothing else exercises
it. Values checked against mpmath's gammainc(a, 0, x); the deep-tail case
(a=4, x=80) reproduces the convergence bug this PR fixes.
2026-08-04 08:25:52 +02:00
gaoflow b3023fd66c Update CHANGELOG for #4945 2026-08-04 08:25:51 +02:00
gaoflow e88cd615cc Fix incomplete gamma convergence for GAMMA.DIST / CHISQ.DIST
The incomplete gamma primitive used a fixed 32-term power series with no
convergence test, so GAMMA.DIST, GAMMADIST, CHISQ.DIST(.RT), GAMMAINV and
CHISQ.INV were grossly wrong once the series argument reached ~32
(e.g. CHISQ.DIST.RT(80, 4) returned 0.806 instead of 1.74e-16).

Replace it with the standard convergence-tested regularized incomplete
gamma: series P(a,x) for x < a+1, continued fraction Q(a,x) for x >= a+1.
CHISQ.DIST.RT now uses Q directly so the right tail stays free of
1 - P cancellation. Consolidates the duplicate copy that already existed
privately in ChiSquared onto the shared primitive.
2026-08-04 08:25:36 +02:00
oleibman a32a22a481 Merge branch 'master' into stancomments 2026-08-03 22:42:32 -07:00
oleibman 8b4b934011 Merge pull request #4946 from gaoflow/fix-gammainv-tail-bracket-clamp
Expand GAMMAINV bracket so tail quantiles are not clamped
2026-08-04 02:43:29 +00:00
oleibman 08eb18d7ae Unset PivotTableCollection at Destruct, plus some Performance Tweaks 2026-08-03 19:05:00 -07:00
saifulislamferoz 2e4cc54a0d Fix corrupt date-grouped pivot table and import ordering
Excel reported sample 3's ByQuarter sheet as corrupt: a date field
group (rangePr groupBy="quarters") was emitted without the date bounds
Excel requires. When no explicit start/end date is supplied, fall back
to the sentinel range (1900-01-01 .. 9999-12-31) so both the sharedItems
(minDate/maxDate) and the rangePr (startDate/endDate) are always present,
matching the <1/1/1900 / >12/31/9999 out-of-range group items.

Also fixes ordered_imports in Worksheet.php (php-cs-fixer CI failure):
the PivotTable\PivotTable use statement is moved before the Sparkline
imports.
2026-08-03 16:16:35 +06:00
oleibman 4bf2f8f326 Merge branch 'master' into stancomments 2026-08-03 00:45:46 -07:00
saifulislamferoz 5efba3ee64 Increase pivot table test coverage
Cover the previously-unexercised code paths flagged by Coveralls:
- writer: month and year date grouping, and a fractional numeric interval
  (the non-integer num() path);
- reader: reading an explicit dataField subtotal attribute back from a saved
  file;
- worksheet: the getPivotTables() alias, addPivotTable(), case-insensitive
  getPivotTableByName(), the no-match lookup, and removePivotTableCollection().
2026-08-03 11:52:58 +06:00
saifulislamferoz 2046913138 Add unit tests for pivot table model accessors
Cover the PivotFieldGroup, PivotField, PivotCacheDefinition and PivotTable
accessors that were not exercised by the reader/builder tests (numeric and
date grouping getters, field-group storage on the cache definition, pivot
field setters, and PivotTable::__toString), restoring code coverage.
2026-08-03 11:52:58 +06:00
saifulislamferoz e5b0477559 Fix PHPStan errors in pivot table tests
Use getSheetByNameOrThrow() instead of the nullable getSheetByName() for
chained calls, assert non-null before dereferencing getCacheDefinition() and
getPivotTableByName(), and replace an inline array_map closure with a typed
helper so PHPStan (level 8) is satisfied.
2026-08-03 11:52:58 +06:00
saifulislamferoz 7d7f5061ae Apply php-cs-fixer style fixes to pivot table files
Shorten @see references to unqualified class names and drop a stray blank
line after the sample header docblock, matching the project's php-cs-fixer
and phpcs rules.
2026-08-03 11:52:58 +06:00
saifulislamferoz 6afe310f8a Add PivotTable samples
Adds runnable samples under samples/PivotTable demonstrating the pivot table
feature, discovered automatically by the sample browser:

- 01_Create_PivotTable: build a basic pivot (row/column/value fields) from a
  source range and save it as Xlsx.
- 02_PivotTable_Page_Filter: add a page (report filter) field.
- 03_PivotTable_Grouping: group a numeric field into ranges and a date field
  by quarter.
- 04_Read_PivotTable: write a pivot, load it back, and inspect the pivot table
  object model (source, row/column/page fields, value aggregation).

Directory is named PivotTable to match the PascalCase convention used by the
other sample categories (Table, Chart, ...).
2026-08-03 11:52:58 +06:00
saifulislamferoz c899e5cb75 Add pivot page (filter) fields and numeric/date grouping
Extends PivotTableBuilder with the two remaining common pivot capabilities.

Page fields: addPageField() places a field on the page (report filter) axis,
and the writer emits a <pageFields> section (in its correct schema position,
after colFields and before dataFields) with the field marked axis="axisPage".

Grouping: a new Worksheet\PivotTable\PivotFieldGroup value object captures how a
field is grouped, and the builder gains groupFieldByNumericRange() (fixed-width
buckets between a start and end number) and groupFieldByDate() (group a date
field by a calendar unit such as quarters or months). The grouping is written
into the pivot cache definition as a <fieldGroup> with <rangePr> and computed
<groupItems>; with refresh-on-load the spreadsheet application materialises the
buckets when it opens the file.

The generated cache definition, workbook wiring and content types remain a
structurally consistent OPC package, and pivots with page fields or grouping
read back into the object model. Tests cover page-field placement/output,
numeric range grouping, date quarter grouping, and validation of unknown
fields.
2026-08-03 11:52:55 +06:00
saifulislamferoz 5aa558b6d6 Add pivot table creation via PivotTableBuilder (Xlsx)
Adds the ability to create a new pivot table from a range of source data,
building on the existing read model and round-trip preservation.

New Worksheet\PivotTable\PivotTableBuilder provides a fluent API: point it at a
source worksheet and range (its first row supplies the field names), place
fields on the row/column axes and add value fields with an aggregation
function, then build() produces a PivotTable and registers it on a target
sheet. Source field names are resolved from the header row (RichText/inline
string headers included), and distinct values are collected for the cache
definition's sharedItems.

The model gains what generation needs: PivotTable::isGenerated(), per-field
data-field captions, subtotal-function constants on PivotField, and sharedItems
on PivotCacheDefinition.

Writer: a new Writer\Xlsx\PivotTable generates the pivotTableDefinition,
pivotCacheDefinition (with refreshOnLoad set) and an empty pivotCacheRecords
part, plus their rels. On save, generated pivot tables are assigned indices
that continue past any preserved pivot parts (so a workbook can mix loaded and
new pivots without collision) and are wired into the worksheet relationships,
workbook <pivotCaches> registry, workbook relationships and content types via
the same unparsed-data path used for preservation. Values are computed by the
spreadsheet application on open via refresh-on-load, so we don't reimplement
the aggregation engine.

Output is a structurally consistent OPC package and reads back into the object
model. Tests cover building, validation errors, the generated parts and
wiring, aggregation attributes, and mixing preserved with generated pivots.
2026-08-03 11:52:45 +06:00
saifulislamferoz 351c5e7f73 Preserve Xlsx pivot tables through a load/save round-trip
Previously, loading an Xlsx file that contained a pivot table and saving it
again silently dropped every pivot part, corrupting the user's pivot tables.
This makes the writer round-trip them intact.

Reader: alongside parsing pivot tables into the object model, the raw pivot
parts are now captured into the unparsed loaded data - the pivot table part
and its rels (per sheet), the pivot cache definition, its rels and the cache
records - each keyed by its original archive path so the relationships between
them stay valid. The workbook <pivotCaches> registry (cacheId -> cache
definition) and the pivot content-type overrides are captured too.

Writer: the preserved parts are re-added to the archive; worksheet
relationships gain a pivotTable relationship, workbook relationships gain a
pivotCacheDefinition relationship, and workbook.xml re-emits <pivotCaches>
with an r:id that matches the regenerated workbook relationship. Content types
are restored via the existing override_content_types pass-through.

The output is a structurally consistent OPC package (all rels and content
types resolve) and is stable across repeated round-trips. Tests cover part
preservation, workbook/rels/content-type wiring, and that the pivot object
model still reads back after a save.
2026-08-03 11:52:30 +06:00
saifulislamferoz 0f318f0aa6 Add read-only object model for Xlsx pivot tables
Introduces a first-class, read-only representation of pivot tables that
already exist in a loaded Xlsx file (issue #4534). Previously pivot tables
were completely inaccessible from the object model.

New model classes under Worksheet\PivotTable:
- PivotTable: name, location, source cache definition and field layout,
  with axis helpers (getRowFields/getColumnFields/getPageFields/getDataFields).
- PivotCacheDefinition: cache id, source worksheet/range and cache field names.
- PivotField: field index, name, axis placement, and data-field aggregation.

Reader\Xlsx\PivotTableReader parses a pivotTableDefinition part and its
associated pivotCacheDefinition part into that model. The main Xlsx reader
discovers pivot parts via worksheet relationships and wires them up (skipped
under setReadDataOnly). Worksheet gains getPivotTableCollection(),
getPivotTables(), addPivotTable(), getPivotTableByName(), getPivotTableNames()
and removePivotTableCollection().

This is inspection-only: it does not create, modify, recalculate or render
pivot tables, and does not change what the writer emits. A minimal pivot-table
fixture and functional tests cover reading name, location, cache source,
fields and axis placement, plus the read-data-only path.
2026-08-03 11:51:43 +06:00
oleibman 63e4e229a3 Merge pull request #4943 from saifulferoz/feature/sparklines
Add support for Excel sparklines
2026-08-03 05:40:02 +00:00
Feroz 21b641b8bc Merge branch 'master' into feature/sparklines 2026-08-02 23:52:33 +06:00
Feroz 8d2cd9f68d Merge branch 'master' into feature/sparklines 2026-08-02 23:37:03 +06:00
oleibman 85be5ac255 Merge pull request #4833 from kemo/perf/xls-reader-optimizations
Optimize XLS (BIFF8) reader performance with reduced per-cell overhead
2026-08-02 07:00:41 +00:00
oleibman 40911aa104 Update Phpstan and Tcpdf
Many problems with Dependabot this month. Phpstan introduced a lot of new "errors". These are now fixed or annotated. I combined this with a change to require comments for `phpstan-ignore`. These won't always be useful, but I think requiring them makes sense.

Tcpdf is more of a non-update. Our composer.json specified `^6.5`. For some reason, Dependabot decided it was okay to change that to `^6.5||^7.0`, which seems presumptuous. (One of the triggers was probably the elimination of Php8.1, since the new product requires 8.2+.) Tcpdf is nominally deprecated, replaced by tc-lib-pdf. Tcpdf 7 passes control to the new product. However, the upgrade is not straightforward. The user needs to supply font files which were formerly distributed with the product, and a code change to define a (shudder) global constant is required. Consequently, Dependabot's upgrade failed its unit tests. While I may evaluate what might be needed at some point in the future, for now I am just updating composer.json to reject Tcpdf 7+.
2026-08-01 22:06:38 -07:00
oleibman 9ef98dfe8f Merge pull request #4951 from PHPOffice/dependabot/composer/friendsofphp/php-cs-fixer-3.95.17
Bump friendsofphp/php-cs-fixer from 3.95.11 to 3.95.17
2026-08-01 14:46:02 +00:00
dependabot[bot] a27503b72d Bump friendsofphp/php-cs-fixer from 3.95.11 to 3.95.17
Bumps [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) from 3.95.11 to 3.95.17.
- [Release notes](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases)
- [Changelog](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/compare/v3.95.11...v3.95.17)

---
updated-dependencies:
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.95.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 11:02:39 +00:00
Vincent Gao c497c12eb3 Evaluate GAMMA.INV via spreadsheet formula in tests; document bounded tail fallback 2026-07-29 04:59:19 +02:00
gaoflow 0b9dff4813 Update CHANGELOG for #4946 2026-07-28 12:18:08 +02:00