* Allow single-cell checks on conditional styles, even when the style is configured for a range of cells
* Work on the CellMatcher logic to evaluate Conditionals for a cell based on its value, and identify which conditional styles should be applied
* Refactor style merging and cell matching for conditional formatting into separate classes; this should make it easier to test, and easier to extend for other CF expressions subsequently
* Added support for containsErrors and notContainsErrors
* Initial work on a wizard to help simplify created Conditional Formatting rules, to ensure that the correct expressions are set
* Further work on extending the Conditional Formatting rules to cover more of the options that are available in MS Excel
* Prevent phpcs-fixer from removing class @method annotations, used to identify the signature for magic methods used in Wizard classes
* Implement `fromConditional()`` method to allow the creation of a CF Wizard from an existing Conditional
* Ensure that xlsx Reader picks up the timePeriod attribute for DatesOccurring CF Rules
* Allow Duplicates/Uniques CF Rules to be recognised in the Xlsx Reader
* Basic Xlsx reading of CF Rules/Styles from <extLst><ext><ConditinalFormattings> element, and not just the <ConditinalFormatting> element of the worksheet
* Add some validation for operands passed to the CF Wizards
- remove any leading ``=` from formulae, because they'll be embedded into other formulae
- unwrap any string literals from quotes, because that's also handled internally
Handle cross-worksheet cell references in cellReferences and Formulae/Expressions
* re-baseline phpstan
* Update Change Log with details of the CF Improvements
Per https://getcomposer.org/doc/06-config.md#allow-plugins, Composer has added an extra layer of security in V2.2, and will start enforcing it in July of this year. Phpcodesniffer uses a plugin and will be affected if composer.json isn't updated before that date.
Co-authored-by: Mark Baker <mark@lange.demon.co.uk>
Fix#2488. When Excel sees this situation, it leaves the value of the cell as null rather than casting to the specified DataType. It doesn't really make sense to change setValueExplicit to adopt this convention; it should be sufficient to recognize the situation in the Reader and act there. The same sort of situation might apply to strings, but I don't see any practical difference between null string and null even if so.
* Refinement for XIRR
Fix#2469. The algorithm used for XIRR is known not to converge in some cases, some of which are because the value is legitimately unsolvable; for others, using a different guess might help.
The algorithm uses continual guesses at a rate to hopefully converge on the solution. The code in Python package xirr (https://github.com/tarioch/xirr/) suggests a refinement when this rate falls below -1. Adopting this refinement solves the problem for the data in issue 2469 without any adverse effect on the existing tests. My thanks to @tarioch for that refinement.
The data from 2469 is, of course, added to the test cases. The user also mentions that an initial guess equal to the actual result doesn't converge either. A test is also added to confirm that that case now works.
The test cases are changed to run in the context of a spreadsheet rather than by direct calls to XIRR calculation routine. This revealed some data validation errors which are also cleaned up with this PR. This suggests that other financial tests might benefit from the same change; I will look into that.
* More Unit Tests
From https://github.com/RayDeCampo/java-xirr/blob/master/src/test/java/org/decampo/xirr/XirrTest.javahttps://github.com/tarioch/xirr/blob/master/tests/test_math.py
Note that there are some cases where the PHP tests do not converge, but the non-PHP tests do. I have confirmed in each of those cases that Excel does not converge, so the PhpSpreadsheet results are good, at least for now. The discrepancies are noted in comments in the test member.
Fix#2442. Although data and styles are handled correctly after removing row(s) or column(s), the dimensions of the removed rows and columns remain behind to afflict their replacements. This PR will take care of removing the dimensions as well.
Dimensions has a _clone method for a deep clone, but all of its properties, as well as the properties of RowDimensions and ColumnDimensions, are scalars, and do not require a deep clone. The method is deleted.
Fix#2373. Excel can handle DateTime/Date/Time as a string if the datatype of the cell is set to "d". The string is, apparently, supposed to follow the ISO8601 spec. Openpyxl can be configured to generate a file with such values, so I've added support and set up unit tests. Excel, naturally, converts such a string input into its numeric representation of the date/time stamp. So will PhpSpreadsheet, so a call to setValueExplicit specifying Date format will actually see the cell wind up with Numeric format - there is no way (and no reason) for the Date type to 'stick'.
* New Error Reported with Phpstan 1.3
Dependabot opened a number of PRs. Most are successful, but this change is necessary to allow PR #2477 to complete successfully, and that is apparently a necessity for PR #2479.
Phpstan 1.3 objected to:
```php
trigger_error($errorMessage, E_USER_ERROR);
return false;
```
It claims the return statement is unreachable. This isn't precisely true - an error handler might allow the return to be reached. At any rate, I have slightly restructured the code so that Phpstan will not object either with 1.2 or 1.3, which should allow the blocked PRs to succeed. There had been no previous tests for what happens when there is a formula error when suppressFormulaErrors is true.
* Scrutinizer
Didn't like effect of changes which Phpstan liked. Hopefully this will work better.
* Improvement
Eliminate added function.
Replace mock tests with real ones when possible. The original tests are all still present; they just take place in a more representative scenario.
After this, there will be 4 remaining uses of mocking. Of these, 3 are needed for scenarios which are otherwise hard to test - WebServiceTest, CellsTest, and SampleCoverageTest. For the other one, AutoFilterTest, I just can't figure out what it's trying to accomplish, so have left it alone.
This change is almost entirely restricted to tests. There is a one-line change in src. When the first argument passed to OFFSET is null or nullstring, the returned value is currently 0. However, according to the documentation for Excel, it should be `#VALUE!`. The code is changed accordingly.
* Rename Two Test Files
When I run unit tests only for Reader/Xlsx, phpunit is issuing a deprecation message because the names of 2 files have an extra dot in them and thus don't match the class name in the file. I do not see these warnings when I run the entire test suite.
* Remove Phpstan Annotations
It was a bit difficult to handle a cast from mixed to string.
* Fix Same Phpstan Problem in One Other Test
This is the only other test case that tries to cast mixed to string.
* Null Passed to AutoFilter SetRange
Fix#2281. Delete auto filter set range to null, but should set it to null string. This causes a deprecation warning in Php8.1.
* Constructor Call Also Sets Range to Null
Should set it to null string.
I noticed, too late, that PR #2422 updated the Release 1.20 section of change log because there was no Unreleased section. Created the missing section, moved the comment for 2422, and added the rest of the changes that have taken place since 1.20.
* General Style Specified in Uppercase in Input Xlsx
Fix#2450. Treat input style GENERAL as if it were expected upper/lowercase.
* Declare Method as Static
Surprised neither Phpstan nor Scrutinizer flagged this.
* Remove Duplicated Statement
Don't know why Scrutinizer didn't flag this the first time.
* Fill Pattern Start and End Colors
Fix#2441. The Fill constructor sets start color to white and end color to black and the Xlsx writer writes these values to the output file. This appears to be the wrong setting for all 7 LIGHT* pattern types, 2 of the 7 DARK* patterns (DARKGRAY and DARKTRELLIS), and 1 of the 3 GRAY patterns (GRAY0625). When the wrong colors are written at save time, those patterns are not as expected. Xls writer does not appear to have the same problem.
The XML does not require either a start or end color, and the omission of these colors in the file being read was responsible for the problem. The code is changed to mimic that behavior by omitting the color tags at write time if they have not changed from when they were created by the Fill constructor (they will be written for gradient or solid patterns regardless).
This is another change which is easier to confirm via samples rather than tests. There are separate samples for Xlsx and Xls; as Excel will be quick to warn you, Xls is not as fully functional as Xlsx with respect to fill patterns. The samples do include a cell where one of the cells (LightGrid in C11) explicitly specifies the "default" colors.
* Scrutinizer
It somehow ascribed to me a problem in code which was unchanged by this PR. Correct it anyhow, along with some Phpstan fixes (errors now ignored because of change).
* Added Tests
Also corrected some docBlock problems with Style/*/parent and getSharedComponent.
* Create 2 Abstract Methods
Scrutinizer complained that 2 methods found in all Supervisor sub-types were not defined in Supervisor. Add abstract methods to satisfy it.
* Scrutinizer Ignoring Typehints
Try this instead.
* Slight Improvement
Better handling of Style->getParent().
* XLSX Image background in comments
* XLSX-Image-Background-In-Comments (#1547)
* Test fixes, convertion for comment sizes from px to pt, fix for setting image sizes from zip, set image type
* Merge remote-tracking branch 'origin/XLSX-Image-Background-In-Comments' into XLSX-Image-Background-In-Comments
* Tests to check reloaded document.
Co-authored-by: Burkov Sergey
* Name Clashes Between Parsed and Unparsed Drawings
This is at least a partial fix for #2396 and #1767 (which has been around for a long time). PhpSpreadsheet renames drawing XML files when it reads them from a spreadsheet. However, when it writes unparsed drawing files, it uses the original names, which can result in a clash with the renamed files. The solution in this PR is to write the unparsed files using the same renaming convention as the the others.
This is an incredibly simple fix, basically a one-line change, for such a long-lived problem. It is conceivable that this PR breaks a more sophisticated file than I have come across, e.g. with multiple unparsed files associated with a single worksheet. However, this PR does fix at least part of the problem for both issues, and causes no regression issues. The changed code was covered in only 2 tests - Reader/XlsxTest testLoadSaveWithEmptyDrawings and Writer/Xlsx/UnparsedDataTest testLoadSaveXlsxWithUnparsedData.
2396 is covered by a new test Unparsed2396Test. I had trouble figuring out what to test for 1767. Since it is a problem that becomes evident only when the output file is opened in Excel, I added a new sample to cover it.
* Sloppy Errors
I neglected to run php-cs-fixer and phpstan, and it bit me.
* Scrutinizer
It's not as good as Phpstan at recognizing problems that can't happen due to previous assertions.
* Scrutinizer Again
It can be really stupid sometimes.
PR #2428 reduced the count of Phpstan errors reported under Php8 from 218 to 13. This PR takes care of those 13, which could not necessarily be handled merely by tweaks to the configuration files.
The commonest problem was that Phpstan under Php7 thinks date_parse can return an array or false, but, under Php8, it thinks it can return only array. The documentation agrees with the Php7 interpretation, but I have not been able to construct a case, in any release of Php, where date_parse returns false. In case of error, it sets elements 'error' and 'error_count' in the returned array. Code is changed to handle either possibility in a manner of which Phpstan will approve.
Other problems are handled through type-hinting.
Fix#2432. Probably for memory reasons, PhpSpreadsheet divides its data into chunks when writing to Mpdf. However, if the first chunk has so many styles that the `body` tag is not included in the chunk, Mpdf will not handle it correctly. Code is changed to ensure that the first chunk always contains the body tag.
Because this error becomes evident only when opening the PDF file itself, it is difficult to write a test case. I have instead added a new sample file which meets the conditions which would have led to the error, and which can be examined to show that it is created correctly.
* Special Characters in Image File Name
Fix#2415. Fix#1470. If path name of image contains anything other than ASCII, or if it contains # or space or probably other exceptions, PhpSpreadsheet creates a file that Excel cannot, for whatever reason, read (it is valid xml). When adding an image to a spreadsheet, Excel does not retain the original path name; PhpSpreadsheet does, but probably shouldn't. It is changed to save the image file in the zip as the MD5 hash of the original path name. This produces a file that Excel can read. In addition, it ensures that, if the image is used in multiple places, it is saved in the Excel file only once.
Because this error becomes evident only when opening the file in Excel, it is difficult to write a test case. I have instead duplicated sample Basic/05... using image files whose names match the reported error conditions.
* Scrutinizer Minor Error
Remove some newly dead code.
Fix#1641. Excel allows explicit hiding of row after filter is applied, but PhpSpreadsheet automatically invokes showHideRows on all auto-filters, preventing users from doing the same. Change to invoke showHideRows only if it hasn't already been invoked, or if filter criteria have changed since it was last invoked. Autofilters read in from an existing spreadsheet are assumed to be already invoked.
This is potentially a breaking change, probably a minor one. The conditions to set up 1641 are probably uncommon, but users who meet those conditions and are happy with the current behavior will see a break. The new behavior is closer to how Excel itself behaves. A new method `reevaluateAutoFilters` is added to `Spreadsheet`; this can be used to restore the old behavior if desired. The new method is added to the documentation, along with a description of how the situation described in 1641 is handled in Excel and PhpSpreadsheet.
While examining Excel's behavior, it became evident that, although a filter is applied to an entire column, it is actually applied only to the rows that are populated when the filter is defined, as can be verified by examining the XML definition of the filter. When you re-apply the filter, rows that have been added since are considered. It would be useful to provide PhpSpreadsheet with a method to do the same. I have added, and documented, `setRangeToMaxRow` to `AutoFilter`.
`ReferenceHelper::insertNewBefore` copies data from one cell to another when adding/removing rows or columns.
It now also respects the data type set for that cell and does not use value binder again.
* Handle a wildcard match that contains a forward slash in the pattern by adding / to the delimiter list of preg_quote
* Fix SUMIF doing a wildcard match on empty cells (NULL)
* Fix compare logic to return false when value is an empty string or NULL (Verified against LibreOffice SUMIF and MATCH handling of empty cells)
As configured, Phpstan running under Php7 reports no errors. However, running under Php8, it reports 218 (!) errors. The vast majority of these are due to two reasons:
- renaming parameters in Php builtin functions in preparation for named parameters.
- using the new class `GdImage` rather than type `resource` as the argument type for many image-based functions.
Regardless of the cause, this will be a problem sooner or later. This PR is an attempt to get ahead of that problem. It tweaks only the Phpstan configuration files, without changing any PhpSpreadsheet code. Php7 continues to report no errors, and the number of errors for Php8 is reduced to 13. Although those 13 can also be tweaked, there is a case to be made that code corrections might be better in at least some of those instances. I will attend to those as one or more PRs after this one.
Because this involves no changes to code, and because Phpstan baseline is a common cause of merge difficulties, I will probably merge this in a day or two, more quickly than I customarily do.
Fix#1691. PhpSpreadsheet allows the setting of different page size and orientation on each worksheet. It also allows the setting of page size and orientation on the PDF writer. It isn't clear which is supposed to prevail when the two are in conflict. In the cited issue, the user expects the PDF writer setting to prevail, and I tend to agree. Code is changed to do this, and handling things in this manner is now explicitly documented.
PhpSpreadsheet uses a default paper size of Letter, and a default orientation of Default (which Excel treats as Portrait). New static routines are added to change the default for sheets created subsequent to such calls. This could allow users to configure these defaults better for their environments. The new functions are added to the documentation.
Fix#2387. Fix#2075. There was substantial refactoring of Writer Xlsx styles in 18.0. An existing static property `$theme` was intended to be shared by both Writer Xlsx and the new Writer Xlsx Styles. However, the initialization of the property in the latter happened later than it should have. This PR makes that initialization happen as soon as the theme has been read. Also, declaring that property as static seems questionable; I have made it an instance member. This small re-factoring makes it possible to now support Themes in tab colors.
Since this PR changes Reader/Xlsx/Styles, add type-hinting throughout that module to eliminate Phpstan/Scrutinizer problems. I also removed method readStyle from Reader/Xlsx, since it was essentially duplicated in Reader/Xlsx/Styles. And I added a small number of tests to ensure that Styles is 100% covered. All of this is necessary in preparation for Namespacing phase 2.
Fix#2385. NumberFormatter is using sprintf on a float, and is seeing inconsistent rounding as a result (it will also occasionally result in `-0`). Change to round the number before presenting it to sprintf.
oleibman said:
The results of uncommenting the statements will often not be successful.
In Excel, if I enter `=MINVERSE({2,0;0,1})` into cell A1, you will get a
`dynamic array` (which we do not yet support) - A1 will contain 0.5, A2
and B1 will contain 0, and B2 will contain 1. There are also `spill`
implications for such a formula. The XML for these cells will be:
``` xml
<row r="1" spans="1:2" x14ac:dyDescent="0.3">
<c r="A1" cm="1">
<f t="array" ref="A1:B2">MINVERSE({2,0;0,1})</f>
<v>0.5</v>
</c>
<c r="B1">
<v>0</v>
</c>
</row>
<row r="2" spans="1:2" x14ac:dyDescent="0.3">
<c r="A2">
<v>0</v>
</c>
<c r="B2">
<v>1</v>
</c>
</row>
```
I believe that the PhpSpreadsheet equivalent of doing this (with the statements
uncommented) is:
```php
$spreadsheet = new Spreadsheet();
$calculation = Calculation::getInstance($spreadsheet);
$calculation::setArrayReturnType(Calculation::RETURN_ARRAY_AS_ARRAY);
$sheet = $spreadsheet->getActiveSheet();
$sheet->getCell('A1')->setValue('=MINVERSE({2,0;0,1})');
$writer = new Xlsx($spreadsheet);
$oufil = 'issue.2343.xlsx';
$writer->save($oufil);
```
But our output file only fills in A1:
```xml
<row r="1" spans="1:1">
<c r="A1">
<f>MINVERSE({2,0;0,1})</f>
<v>0.5</v>
</c>
</row>
```
And, even though A1 has its correct value, note that its `f` tag does not have
a `t` attribute. This is because we never set any formula attributes, except
in Xlsx Reader (see next paragraph), so we do not encounter the `'array'`
condtion for a formula newly added to a spreadsheet.
We do slightly better when we read the first file (as opposed to creating a new
spreadsheet), but we succeed only by accident. Because B1, A2, and B2 are
assigned values in the XML, all 4 cells will have the expected values. But they
are now independent of each other, not part of a dynamic array. When we write
this out, it is almost correct:
```xml
<row r="1" spans="1:2">
<c r="A1">
<f>MINVERSE({2,0;0,1})</f>
<v>0.5</v>
</c>
<c r="B1">
<v>0</v>
</c>
</row>
<row r="2" spans="1:2">
<c r="A2">
<v>0</v>
</c>
<c r="B2">
<v>1</v>
</c>
</row>
```
Again, the `f` tag has no `t` attribute, and it doesn't seem to matter whether we set
RETURN_TYPE_ARRAY or not. I think this particular aspect of the problem might be
relatively easy to fix.
When the fill color property of `DataSeries.plotLabel` using a
DataSeriesValues on a line chart is set, the XLSX file written
is corrupted, and MSExcel2016 removes the drawing1.xml if forced open.
This problem was already documented on issue #589 along with a possible
solution. So all credits go to @madrussa. I am only submitting the PR.
Fixes#589Closes#1930